zoukankan      html  css  js  c++  java
  • Android Learning:数据存储方案归纳与总结

     

    前言

      最近在学习《第一行android代码》和《疯狂android讲义》,我的感触是Android应用的本质其实就是数据的处理,包括数据的接收,存储,处理以及显示,我想针对这几环分别写一篇博客,记得我的学习心得,也希望跟各位新手同学相互努力促进。今天这篇博客,我想介绍一下数据的存储,因为数据的接收,存储,处理以及显示这几环环环相扣,而数据的存储直接关系到数据的处理和显示,所以显得尤为重要。

      所以本文针对数据存储的常见方案和其使用进行了归纳。分为程序内存储和程序间数据访问,程序内存储介绍了文件存储、SharedPreferences存储、数据库存储三种不同的存储方式的优缺点以及区别,用用例子详细说明了各自的用法,重点介绍了数据库存储的操作。 程序间数据访问介绍了内容提供器。

    Android程序内数据存储方案:

      Android系统中主要提供了三种方式用于简单地实现数据持久化功能,即文件存储、SharedPreferences存储以及数据库存储。当然,除了这三种方式之外,还可以将数据保存在手机的SD卡中,不过使用文件存储、SharedPreferences存储以及数据库存储会相对于将数据保存在手机的SD卡中更安全也更简单一些[1]。 

      一、文件存储: 

      文件存储是Android中最基本的一种数据存储方式,它不对存储的内容进行任何的格式化处理,所有数据都是原封不动地保存到文件当中的,因而它比较适合用于存储一些简单的文本数据或二进制数据。如果你想使用文件存储的方式来保存一些较为复杂的文本数据,就需要定义一套自己的格式规范,这样方便于之后将数据从文件中重新解析出来。由于文件存储的方式有着起局限性,在实际工程项目中用的很少,我们也就不具体展开说。  

      二、SharedPreferences存储: 

      不同于文件的存储方式,SharedPreference是使用键值对的方式来存储数据的。也就是说当保存一条数据的时候,需要给这条数据提供一个对应的键,这样在读取数据的时候就可以通过这个键把相应的值取出来。而且SharedPreferences还支持多种不同的数据类型存储,这就是SharedPreference比文件存储的优越性所在。

    三种获取SharedPreferences对象的方法

    • Context类中的getSharedPreferences()方法

          SharedPreferences pref = getSharedPreferences("data", MODE_PRIVATE);

      第一个参数用于指定SharedPreferences文件的名称。第二个参数指定操作模式,MODE_PRIVATE表示只有当前的应用程序才可以对这个SharedPreferences进行读写,MODE_MULTI_PROCESS则一般用于会有多个进程中对同一个SharedPreferences文件进行读写的情况。

    • Activity类中的getPreferences()方法

      跟Context类中的getSharedPreferences()方法很相似,不过只接受一个操作模式参数

    • PreferenceManager类中的getDefaultSharedPreferences()方法

          SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);

      这是一个静态方法,接收Context参数。

    例子:通过SharedPreferences进行读写数据

    shareRead = (Button) findViewById(R.id.share_read);
    shareWrite = (Button) findViewById(R.id.share_write);
    /**
     * pref = PreferenceManager.getDefaultSharedPreferences(this);
     */
    pref = getSharedPreferences("data", MODE_PRIVATE);
    editor = pref.edit();
    shareWrite.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            editor.putString("write", "This is A String");
            /*数据提交*/
            editor.commit();
        }
    });
    shareRead.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            String str = pref.getString("write", null);
            Toast.makeText(MainActivity.this, str, Toast.LENGTH_LONG).show();
        }
    });
    

      

    • 存储数据(shareWrite)的实现

      1. 调用SharedPreferences对象的Edit()方法获取一个SharedPreferences.Editor对象

      2. 向SharedPreferences.Editor对象中添加数据,采用putBoolean、putString等方法

      3. 调用commint()方法将添加的数据提交

    • 获取数据(shareRead)的实现

      1. 直接采用SharedPreferences对象的get方法

      2. get方法接收两个参数,第一个是键,第二个参数是默认值,当传入的键找不大到对应的值,返回默认值

    效果图

       

      sharedPreferences对象与SQLite数据库相比,免去了创建数据库,创建表,写SQL语句等诸多操作,相对而言更加方便,简洁。但是SharedPreferences也有其自身缺陷,比如其只能存储boolean,int,float,long和String五种简单的数据类型,比如其无法进行条件查询等。所以不论SharedPreferences的数据存储操作是如何简单,它也只能是存储方式的一种补充,而无法完全替代如SQLite数据库这样的其他数据存储方式[2]。 

      三、数据库存储

    创建数据库: SQLiteDatabase.execSQL()

    public class MyDatabaseHelper extends SQLiteOpenHelper {
        /*建立一个student的数据表*/
        public static final String CREATE_STUDENT = "create table student ("
                + "id integer primary key autoincrement,"
                + "number integer,"
                + "name text,"
                + "major text)";
    
        private Context myContext;
    
        public MyDatabaseHelper(Context context, String name,
                                SQLiteDatabase.CursorFactory factory, int version) {
            super(context, name, factory, version);
            myContext = context;
        }
    
        @Override
        public void onCreate(SQLiteDatabase db) {
            /*创建数据库*/
            db.execSQL(CREATE_STUDENT);
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        }
    }
    

    更新数据库:onUpgrade()

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
          /*drop table if exists student:发现数据库已经存在student这张表就删除*/ 
          db.execSQL("drop table if exists student");
          onCreate(db);
    }
    

    当表中没有我们所要的数据时:

    添加数据:insert(String table, String nullColumnHack, ContentValues values)

    MyDatabaseHelper dbHelper = new MyDatabaseHelper(this, "student.db, null, 2");
    SQLiteDatabase db = dbHelper. getWritableDatabase();
    ContentValues values = new ContentValues();
    values.put("number", 123456);
    values.put("name", "steve");
    values.put("major", "CS");
    db.insert("student", null, values);
    

    当表中数据已经存在,但是数据需要修改:

    更新数据:update(String table, ContentValues values, String whereClause, String[] whereArgs)

    db.update("student", values,  "name = ?", new String[]{"steve"});

         删除数据:delete(String table, String whereClause, String[] whereArgs)

    db.delete("student", "name = ?", new String[]{"steve"});

    查询数据:

    Cursor query(String table, String[] columns, String selection,String[] selectionArgs, String groupBy, String having,String orderBy)    

         Cursor rawQuery(String sql, String[] selectionArgs) 

    查询表

    query()方法参数 对应SQL部分 描述
    table from table_name 指定查询的表明
    columns select column1,column2 指定查询的列名
    selection where column = value 指定where的约束条件
    selectionArgs - 为where中的占位符提供具体的值
    groupBy group by column 指定需要group by的列
    having having column = value 对group by后的结果进一步约束
    orderBy order by column1, column2 指定查询结果的排序方式
    Cursor cursor = db.query("student", null, "number = ?", new String[] {"123456"}, null, null, null);

      

      到这里,我们可以看到update()、delete()、query()等方法中都传入了String[] whereArgs参数,这是一个字符串数组,也是判断条件,这可以帮助我们在同一个类目中搜索几类关键字的数据

    • 使用事务:事务的特性可以保证让某一系列的操作要么全部完成,要么一个都不会完成

    SQLiteDatabase中包含两个方法控制事务:

    开始事务:beginTransaction()

    结束事务:endTransaction()

    是否在事务中:inTransaction()

    设置事务标志:setTransactionSuccessful()

      表示事物执行成功。如果程序在事务执行中调用该方法设置了事务成功则提交事务,否则程序将会回滚事务。

      注意:

      数据库查看,我们可以通过命令行方式进入SDK/platform-tools,输入adb shell,即可输入数据库的基本指令。但我觉得这种方式并不是很方便,我的做法是,登录SQLite Expert官方网站(http://www.sqliteexpert.com/download.html)下载一个SQLite Expert Personal 3,个人版的是免费的。然后就可以在Android Studio或者Eclipse中进如Android Monitor Device,在File Explorer中找到data/data/包名/database/*.db,点击导出,然后就可以用这个软件打开。       


    Android程序间数据内容提供器:

      上述三种方案是单个程序数据的存储,而我们在有些场景中,需要用到系统应用的数据,比如使用系统的通讯录、短信和媒体库等功能,那这就需要我们使用内容提供器(Content Provider),它可以用于在不同的应用程序之间实现数据共享。

    一、获取其他应用的数据

      内容提供器是通过ContentResolver类来访问内容提供器中共享的数据,ContentResolver是由Context.getContentResolver() 得到的。 

        Cursor cursor = getContentResolver().query(
            uri,
                projection,
                selection,
                selectionArgs,
                sortOrder) ;
    

    查询表

    query()方法参数 对应SQL部分 描述
    uri from table_name 指定查询的表明
    projection where column = value 指定where的约束条件
    selection - 为where中的占位符提供具体的值
    selectionArgs group by column 指定需要group by的列
    orderBy order by column1, column2 指定查询结果的排序方式

       讲到这里,我们会发现,内容提供器的查询方法跟数据库很类似,使用query()方法,不同的是,传进query()方法的参数有所区别。内容提供器传进query的值包含着URI,而URI记录着目标数据的地址,而数据库传进query的值包含着表名,因为数据库是对自身程序文件目录下进行的操作,所以并不需要定位,而内容提供器首先要定位到程序的包名,进而定位到数据文件夹,最终定位到表名,在URI中,我们可以看到最后一个斜杠后就是表名。

    • 内容URI 

    URI的标准格式 

      content://com.example.app.provider/table 

    URI的解析 

      Uri uri = Uri.parse("content://com.example.app.provider/table") 

    URI规则 

        * 表示匹配任意长度的任意字符

        content://com.example.app.provider/*

        # 表示匹配任意长度的数字

        content://com.example.app.provider/table/#

    二、提供应用自身的数据  

    • 内容提供器的六个方法

        1、onCreate()

          初始化内容提供器。完成数据库的创建和升级,只有在ContentResolver尝试访问程序数据才会被初始化

        2、query()

          查询数据。uri确定查哪张表,projection查询列,selection和selectionArgs查询哪些行

        3、insert()

          添加数据

        4、update()

          更新内容提供器已有的数据

        5、delete()

          删除数据

        6、getType()

          根据传入的内容URI来返回相应的MIME类型。

          一个内容URI对应的MIME字符串只要有三部分组成

            (1)必须以vnd开头  

            (2)以路径结尾,后接android.cursor.dir/,以id结尾,后接android.cursor.item/  

            (3)最后接上vnd.<authority>.<path>        

    • 匹配内容URI

        UriMatcher类

        addURI()方法,这个方法接受三个参数,分别把权限、路径和一个自定义代码传进去

        match()方法,将Uri对象传入,返回值是某个能够匹配这个Uri对象说对应的自定义代码

      内容提供类的核心是通过URI对象来定位数据的,但数据定位成功之后,那么就可以用类似于数据库操作的手段进行读取。如果想共享自身的数据,也可以通过URI对象,抛出自己的位置,等待其他程序定位到自身获取数据 

    总结:   

    存储方式 用途 特点
    文件存储 存储一些简单的文本数据或二进制数据 不对存储的内容进行任何的格式化处理
    SharedPreferences存储 存储boolean,int,float,long和String五种简单的数据类型,数据量小 方便,简洁,使用键值对的方式来存储数据,支持多种不同的数据类型存储,但不能条件查询
    数据库存储 数据量大,且有条件 功能强大,条件查询,数据的增删改查,但使用较为复杂
    内容提供器 跨程序之间的数据交换 通过URI对象来定位数据源

     

    [1] 郭霖. 第一行代码 Android[J]. 2014.

    [2] 大气象.Android四种存储方式.http://www.cnblogs.com/greatverve/archive/2011/12/27/android-sharedpreference-file-SQlite-contentprovider.html

  • 相关阅读:
    nodejs ---day01
    面向对象
    面向对象
    面向对象
    webpack
    webpack
    webpack
    模块化 (ESM) --- day02
    模块化 --- day01
    轮播图(淡入淡出切换)
  • 原文地址:https://www.cnblogs.com/danbing/p/5164242.html
Copyright © 2011-2022 走看看