本章继续讲解在Android开发中,数据的存储与管理。涉及知识点:SQLite,SwipeRefreshLayout控件刷新。
练习使用SQLite
图1
图2
图3
图4
图5
简要说明:通过左侧滑动导航界面(图5),可以选择登陆页面(图1)和登陆列表页面(图2)。在登陆成功后,会跳转到登录列表界面。通过选择退出,可清除当前用户的登录状态。登录列表,下拉界面可以刷新页面信息(图3)。
SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。
SQLite由以下几个部分组成:SQL编译器、内核、后端及附件。SQLite通过利用虚拟机和虚拟数据库引擎(VDBE),是调试、修改和扩展SQLite的内核变得更加方便。所有SQL语句都被编译成易读的、可以在SQLite虚拟机中执行的程序集。SQLite的整体结构图如下:
SQLite在数据类型存储方面,目前支持如下类型字段: VARCHAR(10),NVARCHAR(15),TEXT,INTEGER,FLOAT,BOOLEAN,CLOB,BLOB,TIMESTAMP,NUMERIC(10,5),VARYING CHARACTER (24),NATIONAL VARYING CHARACTER(16)。
Android项目中,数据库生成后,存储在/data/data/[PACKAGE_NAME]/databases目录下。
以上方法的第一个参数是表示要操作的表名;
insert中的第二个参数表示如果插入的数据每一列都为空的话,需要指定此行中某一列的名称,系统将此 列设置为NULL,不至于出现错误;
insert中的第三个参数是ContentValues类型的变量,是键值对组成的Map,key代表列 名,value代表该列要插入的值;
update的第二个参数也很类似,只不过它是更新该字段key为最新的value值,
第三个参数 whereClause表示WHERE表达式,比如“age > ? and age < ?”等,最后的whereArgs参数是占位符的实际参数值;
delete方法的参数和update一样;
db.query传入各种参数表示查询,他们同时返回一个Cursor对象,代表数据集的游标。
除以上基本sql操作语句外,SQLite还支持事务操作,如以下操作使用:
1 public void TestTransaction(List<Person> persons) { 2 db.beginTransaction(); //开始事务 3 try { 4 for (Person person : persons) { 5 db.execSQL("INSERT INTO person VALUES(null, ?, ?, ?)", new Object[]{person.name, person.age, person.info}); }
db.setTransactionSuccessful(); //设置事务成功完成 6 } finally { 7 db.endTransaction(); //结束事务 8 } 9 }
各种下拉控件,下拉操作在Android开发中,已经是层出不穷。google终于忍不住推出了自己的下拉组件SwipeRefreshLayout,它很轻巧,很灵活,操作很简单。
swipeRefreshLayout这个类是在放在 android-support-v4.jar里面的。SwipeRefreshLayout组件只接受一个子组件:即需要刷新的那个组件。它使用一个侦听机制来通知拥有该组件的监听器有刷新事件发生,换句话 说我们的Activity必须实现通知的接口。该Activity负责处理事件刷新和刷新相应的视图。一旦监听者接收到该事件,就决定了刷新过程中应处理 的地方。如果要展示一个“刷新动画”,它必须调用setRefrshing(true)
,否则取消动画就调用setRefreshing(false)
。
<android.support.v4.widget.SwipeRefreshLayout android:id="@+id/sr" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" <FrameLayout android:id="@+id/fl_content" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@id/line" /> </RelativeLayout> </android.support.v4.widget.SwipeRefreshLayout>
sr = (SwipeRefreshLayout) findViewById(R.id.sr); sr.setColorSchemeResources(android.R.color.holo_blue_bright, android.R.color.holo_green_light, android.R.color.holo_orange_light, android.R.color.holo_red_light); sr.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { appLoginDetailFragment(); //需要刷新时的操作 sr.setRefreshing(false); } });
Android数据库操作项目Demo结构图如下所示:
数据库处理放在db包,dbhelper是建立数据库的基本操作,包括建表语句;clssqlite表示提供数据库查询,打开等通用操作模板。
登录处理要求:模拟登录成功后,将登录的用户名及登录状态(登录中)写入数据库,保存所有用户登录的历史,但一个用户名只保留一条记录。所以在登录处理时,需要先检查数据表中是否含该登录账户的信息,核心代码如下:
1 private void init() 2 { 3 try { 4 db = new clssqlite(); 5 db.openDB(getActivity()); 6 login_on.setOnClickListener(new View.OnClickListener() { 7 @Override 8 public void onClick(View arg0) { 9 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 这里的格式可以自己设置 10 // format()方法是用来格式化时间的方法 11 Date datenow = new Date(); 12 String returnTime = format.format(datenow); 13 String account = operator.getText().toString(); 14 String passwords = password.getText().toString(); 15 //检测是否含有该账户 16 int loginstatus = db.checklogin("select count(*) as data from LoginData where account='"+account+"' "); 17 try {Thread.sleep(400); 18 } catch (InterruptedException e) { 19 e.printStackTrace();} 20 String sql = "insert into LoginData (account,password,loginstatus,logintime) values ('" + account + "','" + passwords + "',1,'" + returnTime + "') "; 21 if (loginstatus > 0) 22 sql = "update LoginData set loginstatus=1 , logintime='" + returnTime + "' where account='"+account+"' "; 23 db.openDB(getActivity()); 24 if(db.executeSQL(sql)>=0) 25 { 26 //保存登录名 27 result.setText("登录成功"); 28 account_save.edit().putString("account", account).commit(); 29 ((MainActivity) mContext).appLoginDetailFragment(); 30 ((MainActivity) mContext).setToolbarTitle("登录列表"); 31 }else { 32 result.setText("登录失败"); 33 }} 34 }); 35 }catch (Exception ex) 36 { 37 result.setText("登录异常");} 38 }
这个知识利用上一章的SharedPreferences存储即可,在登录成功后,根据代码account_save.edit().putString("account", account).commit();完成用户名保存。
在退出操作时,需要先验证用户是否已经登录了,若登录了,更新数据表中的登录状态字段即可。核心代码如下:
1 public boolean onOptionsItemSelected(MenuItem item) { 2 int id = item.getItemId(); 3 //退出处理 4 if (id == R.id.action_loginoutmode) { 5 db.openDB(this); 6 String account=LoginFragment.account_save.getString("account","00000"); 7 int loginstatus = db.checklogin("select count(*) as data from LoginData where account='"+account+"' and loginstatus=1 "); 8 if(loginstatus>0) 9 { 10 String sql="update LoginData set loginstatus=0 where account='"+account+"' "; 11 db.openDB(this); 12 db.executeSQL(sql); 13 appLoginDetailFragment(); 14 Toast.makeText(getApplicationContext(), "退出登录成功", Toast.LENGTH_SHORT).show(); 15 } 16 else 17 { 18 Toast.makeText(getApplicationContext(), "还未登录", Toast.LENGTH_SHORT).show(); 19 } 20 } 21 return super.onOptionsItemSelected(item); 22 }
登录状态展示是把数据表中存储的字段信息,展示在界面上。其中,对于页面刷新操作,当listview拉动到顶部时,触发刷新事件,相关代码如下:
1 listView.setOnScrollListener(new AbsListView.OnScrollListener() { 2 @Override 3 public void onScrollStateChanged(AbsListView view, int scrollState) { 4 } 5 @Override 6 public void onScroll(AbsListView view, int firstVisibleItem, 7 int visibleItemCount, int totalItemCount) { 8 if (listView != null && listView.getChildCount() > 0) { 9 boolean enable = (firstVisibleItem == 0) && (view.getChildAt(firstVisibleItem).getTop() == 0); 10 //调用刷新控件 11 ((MainActivity) mContext).setSwipeRefreshEnable(enable); 12 } 13 } 14 });
本项目源代码在360云盘上,开发环境为 Android Studio 2.0 beta 7。
https://yunpan.cn/cYamkZG3sq9jf 访问密码 f3d5。文件名称:android数据库存储操作demo。