Android | DataStrorage 与 ContentProvider
Android DataStorage And ContentProvider
数据持久化
存储方式 | |
---|---|
SharedPreferences | 在键值对中存储私有原始数据 |
文件存储-内部存储 | 在设备内存中存储私有数据 |
文件存储-外部存储 | 在共享的外部存储中存储公共数据 |
SQLite 数据库 | 在私有数据库中存储结构化数据 |
SharedPreferences
使用键值对的方式来存储数据,将数据存储到 SharedPreferences
中有以下几种方式:
Context.getSharedPreferences(String name, int mode)
方法:第一个参数用于指定SharedPreferences
文件的名称,如果指定的文件不存在则会创建一个,SharedPreferences
文件都是存放在/data/data/<packagename>/shared_prefs/
目录下的,第二个参数用于指定操作模式。Activity.getPreferences(int mode)
方法:接收一个操作模式参数,自动将当前Activity
的类名作为SharedPreferences
的文件名。储存数据分三步,第一步调用SharedPreferences
对象edit()
方法获取一个对象,第二部利用形如putString()
的方法向对象中添加数据,第三步调用apply()
方法将添加的数据提交,完成数据的存储。PreferenceManager.getDefaultSharedPreferences(Context)
方法:以包名加上_preferences
作为文件名,以MODE_PRIVATE
模式创建SP
文件,即packgeName_preferences.xml
。
在存储时用到的 SharedPreferences.Editor
中的每一种 put
方法都对应着一个 get
方式去读取数据,接受两个参数,一个是键,另一个是找不到相应键值时返回的默认值。
文件存储
不对存储的内容进行任何格式化处理,所有数据都是原封不动地保存到文件当中。并不适合用于保存一些较为复杂的结构型数据。
Context
类中提供了一个 openFileOutput()
方法,可以用于将数据存储到指定的文件中。这个方法接收两个参数:第一个参数是文件名,在文件创建的时候使用,注意这里指定的文件名不可以包含路径,因为所有的文件都默认存储到 /data/data/<package name>/files/
目录下;第二个参数是文件的操作模式,主要有 MODE_PRIVATE
和 MODE_APPEND
两种模式可选,默认是 MODE_PRIVATE
,表示当指定相同文件名的时候,所写入的内容将会覆盖原文件中的内容,而 MODE_APPEND
则表示如果该文件已存在,就往文件里面追加内容,不存在就创建新文件。openFileOutput()
方法返回的是一个 FileOutputStream
对象,得到这个对象之后就可以使用 Java流
的方式将数据写入文件中。
Context
类中还提供了一个 openFileInput()
方法,用于从文件中读取数据,接收一个参数,即要读取的文件名,然后系统会自动到 /data/data/<package name>/files/
目录下加载这个文件并返回一个 FileInputStream
对象,得到这个对象之后,再通过流的方式就可以将数据读取出来。
SQLite 数据库存储
Android
提供了一个 SQLiteOpenHelper
帮助类,借助这个类可以非常简单地对数据库进行创建和升级。SQLiteOpenHelper
中有两个抽象方法:onCreate()
和 onUpgrade()
。我们必须在自己的帮助类里重写这两个方法,然后分别在这两个方法中实现创建和升级数据库的逻辑。SQLiteOpenHelper
中还有两个非常重要的实例方法:getReadableDatabase()
和 getWritableDatabase()
。这两个方法都可以创建或打开一个现有的数据库(如果数据库已存在则直接打开,否则要创建一个新的数据库),并返回一个可对数据库进行读写操作的对象。
SQLite
支持的数据类型包括:integer
表示整型,real
表示浮点型,text
表示文本类型,blob
表示二进制类型。primary key
关键字设置主键。
Android
支持直接通过 SQL
来进行数据的增删查改,还提供了简单的辅助方式进行CRUD操作
:
insert
:SQLiteDatabase
中提供了一个insert()
方法,专门用于添加数据。它接收3个参数:第一个参数是表名;第二个参数用于在未指定添加数据的情况下给某些可为空的列自动赋值NULL
;第三个参数是一个ContentValues
对象,它提供了一系列的put()
方法重载,用于向ContentValues
中添加数据,只需要将表中的每个列名以及相应的待添加数据传入即可。delete
:SQLiteDatabase
中提供了一个delete()
方法,专门用于删除数据。这个方法接收3个参数:第一个参数是表名;第二、第三个参数用于约束删除某一行或某几行的数据,不指定的话默认会删除所有行。select
:SQLiteDatabase
中提供了一个query()
方法用于对数据进行查询,需要的参数很多,在下表中列出并与SQL
做出比较。update
:SQLiteDatabase
中提供了一个update()
方法,用于对数据进行更新。这个方法接收4个参数:第一个参数是表名,指定更新哪张表里的数据;第二个参数是ContentValues
对象,要把更新数据在这里组装进去;第三、第四个参数用于约束更新某一行或某几行中的数据,不指定的话默认会更新所有行。
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 | 指定查询结果的排序方式 |
ContentProvider 概念
主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访问数据的安全性。
访问其他程序中数据
对于每一个应用程序来说,如果想要访问 ContentProvider
中共享的数据,就一定要借助 ContentResolver
类,可以通过 Context
中的 getContentResolver()
方法获取该类的实例。ContentResolver
中提供了一系列的方法用于对数据进行增删改查操作,其中 insert()
方法用于添加数据,update()
方法用于更新数据,delete()
方法用于删除数据,query()
方法用于查询数据。
// 外部进程 向 ContentProvider 中添加数据
public Uri insert(Uri uri, ContentValues values);
// 外部进程 删除 ContentProvider 中的数据
public int delete(Uri uri, String selection, String[] selectionArgs);
// 外部进程 更新 ContentProvider 中的数据
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs);
// 外部应用 获取 ContentProvider 中的数据
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);
这4个方法由外部进程回调,并运行在 ContentProvider
进程的 Binder线程池
中(不是主线程).
通过 URI(统一资源标识符)
分别不同App,协议名为 content
。“主机名”为包名,路径为需要访问的数据库表。
/**
[协议名]://[用户名]:[密码]@[主机名]:[端口]/[路径]?[查询参数]#[片段ID]
content://com.example.app.provider/table1
*/
URI uri = URI.parse("content://com.example.app.provider/table1");
总体使用逻辑如下:
URI uri = URI.parse("content://com.example.app.provider/table1");
ContentResolver resolver = context.getContentResolver();
ContentValues values = new ContentValues();
values.put("_id", 1);
values.put("name", "values1");
resolver.insert(uri, values);
创建 ContentProvider
如果想要实现跨程序共享数据的功能,可以通过新建一个类去继承 ContentProvider
的方式来实现。ContentProvider
类中有6个抽象方法,我们在使用子类继承它的时候,需要将这6个方法全部重写。
// 外部进程 向 ContentProvider 中添加数据
public Uri insert(Uri uri, ContentValues values);
// 外部进程 删除 ContentProvider 中的数据
public int delete(Uri uri, String selection, String[] selectionArgs);
// 外部进程 更新 ContentProvider 中的数据
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs);
// 外部应用 获取 ContentProvider 中的数据
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder);
// ContentProvider 创建后或打开系统后其它进程第一次访问该 ContentProvider 时,由系统进行调用
public boolean onCreate();
// 得到数据类型,即返回当前 Url 所代表数据的 MIME 类型
public String getType(Uri uri) {
//在此匹配URI
URIMatcher.match(uri);
}
在注册创建的 ContentProvider
时需要将授权信息填写到 AndroidManifest
中
<provider
android:name="MyProvider"
android:authorities="com.example.mycontentprovider"
/>