文件存储
内部存储与外部存储
应用的存储区域在逻辑上分为内部存储和外部存储,机身存储和 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的数据变化 |