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

 

posted @ 2016-01-29 16:11  coderbinbin  阅读(1061)  评论(0编辑  收藏  举报