android 数据存储Ⅱ

本章继续讲解在Android开发中,数据的存储与管理。涉及知识点:SQLite,SwipeRefreshLayout控件刷新。

1.功能需求

练习使用SQLite

  •  做一个登录界面,数据库字段包含用户名、密码以及是否登录中的状态
  • 模拟登录成功后,将登录的用户名及登录状态(登录中)写入数据库,并跳转新页面,有退出按钮
  • 当点击退出时,将当前用户登录中的状态清除
  • 下一次登录时,显示上一次登录的用户名
  • 保存所有用户登录的历史,但一个用户名只保留一条记录

2.软件实现

                   图1

                   图2

                    图3

                    图4

                    图5

    简要说明:通过左侧滑动导航界面(图5),可以选择登陆页面(图1)和登陆列表页面(图2)。在登陆成功后,会跳转到登录列表界面。通过选择退出,可清除当前用户的登录状态。登录列表,下拉界面可以刷新页面信息(图3)。

3.相关知识

(1)SQLite简介

    SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。

    SQLite由以下几个部分组成:SQL编译器、内核、后端及附件。SQLite通过利用虚拟机和虚拟数据库引擎(VDBE),是调试、修改和扩展SQLite的内核变得更加方便。所有SQL语句都被编译成易读的、可以在SQLite虚拟机中执行的程序集。SQLite的整体结构图如下:

(2)SQLite性能

  • 在数据存储方面,袖珍型的SQLite可以支持高达2TB大小的数据库,每个数据库都是以单个文件的形式存在,这些数据都是以B-Tree的数据结构形式存储在磁盘上。
  • 在事务处理方面,SQLite通过数据库级上的独占性和共享锁来实现独立事务处理。这意味着多个进程可以在同一时间从同一数据库读取数据,但只有一个可以写入数据。在某个进程或线程想数据库执行写操作之前,必须获得独占锁。在获得独占锁之后,其他的读或写操作将不会再发生。
  • SQLite采用动态数据类型,当某个值插入到数据库时,SQLite将会检查它的类型,如果该类型与关联的列不匹配,SQLite则会尝试将该值转换成该列的类型,如果不能转换,则该值将作为本身的类型存储,SQLite称这为“弱类型”。但有一个特例,如果是INTEGER PRIMARY KEY,则其他类型不会被转换,会报一个“datatype missmatch”的错误。

(3)SQLite支持字段类型

    SQLite在数据类型存储方面,目前支持如下类型字段: VARCHAR(10),NVARCHAR(15),TEXT,INTEGER,FLOAT,BOOLEAN,CLOB,BLOB,TIMESTAMP,NUMERIC(10,5),VARYING CHARACTER (24),NATIONAL VARYING CHARACTER(16)。

(4)SQLite操作数据规则

    Android项目中,数据库生成后,存储在/data/data/[PACKAGE_NAME]/databases目录下。

1.添加、更新和删除数据时,可使用如下通用语句
  • db.executeSQL(String sql);  
  • db.executeSQL(String sql, Object[] bindArgs);//sql语句中使用占位符,然后第二个参数是实际的参数集 
2.专用sql操作语句
  • db.insert(String table, String nullColumnHack, ContentValues values); 
  • db.update(String table, Contentvalues values, String whereClause, String whereArgs); 
  • db.delete(String table, String whereClause, String whereArgs);
  • db.rawQuery(String sql, String[] selectionArgs); 
  • db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy);
  • db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit);
  • db.query(String distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having);

     以上方法的第一个参数是表示要操作的表名;

     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 }

(4)SQLite通用sql语句与专用模块操作对比

  • db.executeSQL(String sql),利用这种方式,对于熟练写sql语句的程序员,可以很快速的写sql语句。加快开发速度。但是,这样的sql语句耦合性太高,不灵活,一旦数据库字段修改,对应业务也需要跟着改。
  • 利用专用的操作语句,相对来说,不是直接写sql语句,需要传入不同的表,字段等信息,相对来说麻烦,但它的优点是降低了系统业务模块与数据库之间的耦合性,在数据库设计方面,如果规划的好,在做数据库字段,修改,新增时,可以不用或者只修改很少一部分业务逻辑代码。

(5)SwipeRefreshLayout简介

    各种下拉控件,下拉操作在Android开发中,已经是层出不穷。google终于忍不住推出了自己的下拉组件SwipeRefreshLayout,它很轻巧,很灵活,操作很简单。

    swipeRefreshLayout这个类是在放在 android-support-v4.jar里面的。SwipeRefreshLayout组件只接受一个子组件:即需要刷新的那个组件。它使用一个侦听机制来通知拥有该组件的监听器有刷新事件发生,换句话 说我们的Activity必须实现通知的接口。该Activity负责处理事件刷新和刷新相应的视图。一旦监听者接收到该事件,就决定了刷新过程中应处理 的地方。如果要展示一个“刷新动画”,它必须调用setRefrshing(true),否则取消动画就调用setRefreshing(false)

(6)SwipeRefreshLayout使用

1.布局文件中加入SwipeRefreshLayout控件,把需要刷新的视图放在控件里面,如刷新一个Fragment视图:
<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>
2.后台代码中操作如下:
 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);
            }
        });

 4.项目核心代码解析

Android数据库操作项目Demo结构图如下所示:

(1)数据库处理

    数据库处理放在db包,dbhelper是建立数据库的基本操作,包括建表语句;clssqlite表示提供数据库查询,打开等通用操作模板。

(2)登录处理

    登录处理要求:模拟登录成功后,将登录的用户名及登录状态(登录中)写入数据库,保存所有用户登录的历史,但一个用户名只保留一条记录。所以在登录处理时,需要先检查数据表中是否含该登录账户的信息,核心代码如下:

 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     }

(3)显示上一次登录的用户名

    这个知识利用上一章的SharedPreferences存储即可,在登录成功后,根据代码account_save.edit().putString("account", account).commit();完成用户名保存。

(4)退出清空登录状态

    在退出操作时,需要先验证用户是否已经登录了,若登录了,更新数据表中的登录状态字段即可。核心代码如下:

 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     }

(5)登录信息展示

    登录状态展示是把数据表中存储的字段信息,展示在界面上。其中,对于页面刷新操作,当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         });

5.项目源代码下载

本项目源代码在360云盘上,开发环境为 Android Studio 2.0 beta 7。

https://yunpan.cn/cYamkZG3sq9jf  访问密码 f3d5。文件名称:android数据库存储操作demo。

 

posted @ 2016-04-08 16:17  无涯Ⅱ  阅读(475)  评论(0编辑  收藏  举报