文件存储
内部存储与外部存储
应用的存储区域在逻辑上分为内部存储和外部存储,机身存储和 SD 卡存储逻辑上都属于外部存储
应用在两个存储区域通过包名来标识,当删除应用时,两个存储区域的对应包名文件夹也会删除
-
内部存储
/data
目录,存储 SharedPreference 和 SQLite 数据库,包含 files 和 cache 目录,非 root 手机中不可见 -
外部存储
/storage
目录,可在文件管理器中访问,包名文件夹位于/storage/**/Android/data/
下,包名文件夹中包含 files 和 cache 目录读写外部存储时需要添加权限
1
2<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
内部存储获取方法:通过 Context 类获取
getDir(name, mode)
:在 data 目录下获取或创建名称为 name 的目录getFilesDir()
:返回内部存储的 files 目录getCacheDir()
:返回内部存储的 cache 目录Environment.getDataDirectory()
:返回 data 目录(内部存储根目录)
外部存储获取方法:通过 Context 类获取
Environment.getExternalStorageDirectory()
:获取外部存储根目录Environment.getExternalStoragePublicDirectory("")
:获取外部存储根目录getExternalFilesDir()
:获取外部存储的 files 目录及其子目录getExternalCacheDir()
:获取外部存储的 cache 目录
其他目录
Environment.getDownloadCacheDirectory()
:获取/cache
目录Environment.getRootDirectory()
:获取/system
目录
文件基本操作
文件的操作模式
MODE_PRIVATE
:默认模式,表示该文件只能被应用本身访问,重新写入会覆盖原内容MODE_APPEND
:追加模式MODE_WORLD_READABLE
:当前文件可被其他应用读取MODE_WORLD_WRITEABLE
:当前文件可被其他应用写入
内部存储文件操作方法:Context 类方法,流操作同 Java
openFileOutput(filename, mode)
:打开文件输出流,文件位于内部存储 files 目录中openFileInput(filename)
:打开文件输入流,文件位于内部存储 files 目录中
外部存储文件操作:获取外部存储目录后,通过文件名获取 File 对象,操作文件流
SharedPreferences
SharedPreferences 使用键值对进行存储,存储在内部存储中,使用 XML 格式管理文件,通常用于配置信息存储
获取 SharedPreferences 对象
-
context.getSharedPreferences(name, mode)
mode 参数只选
MODE_PRIVATE
,表示只有当前应用程序对该对象进行读写 -
activity.getSharedPreferences(mode)
文件名默认为当前 Activity 的类名
存储数据
- 调用 SharedPreferences 对象的
edit()
,获取 Editor 对象 - 调用 Editor 对象的
putString
,putBoolean
等方法添加数据,参数为键值对 - 调用
commit()
提交数据
1 | SharedPreferences sp = context.getSharedPreferences("my_sp", MODE_PRIVATE); |
读取数据:调用 SharedPreferences 对象的 getString
,getInt
等方法
1 | SharedPreferences sp = context.getSharedPreferences("my_sp", MODE_PRIVATE); |
SQLite 数据库
SQLite 是一个轻量级关系型数据库,数据库文件存放在 /data/data/<packagename>/databases/
目录下
SQLite 中的三个核心类
SQLiteOpenHelper
:用于管理数据库,使用时继承该类,重写它的onCreate()
和onUpgrade()
方法,定义数据库创建和更新的操作SQLiteDatabase
:数据库访问类,通过该类方法操作数据库Cursor
:数据库记录指针,可用于遍历结果集
数据库管理
通过 SQLiteOpenHelper
类的实例方法可获取 SQLiteDatabase
数据库对象,首次调用时会调用 onCreate()
getReadableDatabase()
:以只读方式打开数据库getWritableDatabase()
:以可写方式打开数据库,当数据库不可写入时,调用会抛出异常
继承 SQLiteOpenHelper
示例
1 | public class MyDBOpenHelper extends SQLiteOpenHelper { |
数据库操作
调用 SQLiteDatabase
对象方法来操作数据库
SQL 语句
execSQL
:执行 SQL 语句,传入 SQL 语句字符串和占位符参数,SQL 语句中占位符是?
问号rawQuery
:执行 SQL 语句查询,传入 SQL 语句字符串和占位符参数,返回一个 Cursor 对象,用于遍历结果集
添加数据
调用 insert()
,第一个参数为表名,第二个参数为将未指定数据的可空列自动赋值为 null,第三个参数为一个 ContentValues
对象,表示一个键值对
1 | ContentValues values = new ContentValues(); |
更新数据
调用 update()
,第一个参数为表名,第二个参数是 ContentValues
对象,表示修改后的数据,第三、四个参数用于 where 约束,不指定默认更新所有行
1 | ContentValues values = new ContentValues(); |
删除数据
调用 delete()
,第一个参数为表名,第二、三个参数指定约束,不指定默认删除所有行
1 | db.delete("person", "personid = ?", new String[]{"3"}); |
查询操作
调用 query()
,传入参数指定子句或约束,声明如下
1 | public Cursor query( |
- table:指定表名
- columns:指定列名
- selection:指定 where 条件
- selectionArgs:为 where 条件的占位符提供值
- groupBy:指定需要 groupby 的列
- having:having 子句
- orderby:指定排序的列
- limit:指定 limit 子句
Cursor 指针
query 方法和 rawQuery 方法返回一个 Cursor 对象,通过该对象获取数据
move(offset)
:向前或向后移动指定行数,负数表示向前移动moveToFirst()
:使 cursor 移动到第一行,返回 true 表示有数据moveToLast()
:使 cursor 移动到最后一行,返回 truemoveToNext()
:使 cursor 移动到下一行,返回 true 表示下一行有数据moveToPrevious()
:使 cursor 移动到上一行getCount()
:返回总行数isFirst()
:是否是第一行isLast()
:是否是最后一行moveToPosition(int)
:移动到指定行getColumnIndex(String)
:获取指定列的列索引getXXX(int)
:返回当前行的指定列索引的数据
使用事务
事务可以使一组操作变为原子操作
beginTransaction()
:开启事务endTransaction()
:关闭事务
1 | SQliteDatabase db = helper.getWritableDatabase(); |
ContentProvider 数据共享
Android 应用通过 ContentProvider 来实现应用间共享数据

URI
URI 为统一资源标识符,主要由 scheme、authority 和 path 组成,使用 ContentProvider 时,authority 通常为 packagename.provider

Android 常用的 scheme
- content:本地资源
- file:本地文件
- http:网络资源
- tel:打电话
- smsto:发送短信
URI 通配符
- * 表示匹配任意长度的任意字符
- #表示匹配任意长度的数字
Uri.parse()
方法可以将 URI 字符串解析为 Uri 对象
访问 ContentProvider
通过 ContentResolver 类访问其他程序的 ContentProvider,调用 Context 的 getContentResolver()
获取实例
基本操作方法
-
添加数据
1
Uri insert(Uri uri, ContentValues values)
-
删除数据:通过 where 子句添加约束
1
int delete(Uri uri, String where, String[] args)
-
查询数据
1
2
3
4
5
6
7Cursor query(
Uri uri,
String[] projection,
String selection,
String[] selectionArgs,
String sortOrder
) -
更新数据
1
int update(Uri uri, ContentValues values, String where, String[] selectionArgs)
Android11 后,在访问其他程序的 ContentProvider 需要在 AndroidManifest.xml
中声明 queries
标签
1 | <queries> |
自定义 ContentProvider
自定义 ContentProvider 用于给其他程序提供数据访问接口
实现 ContentProvider
自定义继承 ContentProvider 的类,重写六个方法,也可默认空实现
-
onCreate()
:在初始化时调用,用于创建数据库或升级数据库,返回初始化是否成功 -
query()
:查询,结果放入 Cursor 对象返回 -
insert()
:添加数据,返回这条新纪录的 URI -
update()
:更新数据,返回受影响的行数 -
delete()
:删除数据,返回被删除的行数 -
getType()
:返回传入的 URI 对应的 MIME 类型
自定义 ContentProvider 需要在 AndroidManifest.xml
中注册
1 | <provider |
URI 注册
在 ContentProvider 中需要借助 UriMatcher 类注册特定的 URI
调用 addURI(authority, path, code)
,该方法将 URI 与一个自定义编码 code 绑定起来,调用 match(uri)
时返回 code,即 URI 为 content://authority/path
时,match 方法返回注册的 code
1 | UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH); |
其他工具类
ContentUris 类:URI 相关处理
withAppendedId(uri, int)
:在 URI 后追加一个 idparseId(uri)
:解析 URI 中的 id
ContentObserver 类:用于将 ContentProvider 内的数据变化通知给 ContentResolver
1 | resolver.registerContentObserver(uri); // resolver注册观察者,观察URI的数据变化 |