android 数据存储Ⅱ
Published on 2016-04-08 16:17 in 暂未分类 with 无涯Ⅱ

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 @   无涯Ⅱ  阅读(478)  评论(0编辑  收藏  举报
    编辑推荐:
    · 如何编写易于单元测试的代码
    · 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
    · .NET Core 中如何实现缓存的预热?
    · 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
    · AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
    阅读排行:
    · 周边上新:园子的第一款马克杯温暖上架
    · Open-Sora 2.0 重磅开源!
    · 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
    · Ollama——大语言模型本地部署的极速利器
    · DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
    点击右上角即可分享
    微信分享提示