1 SharedPreferences和Editor
@1 SharedPreferences和SharedPreferences.Editor解读
SharedPreferences用于存储类似配置信息的内容,主要是简单的键值对(key-value)。
对于数据存储,无非是 读和写。关于SharedPreferences存储数据:
- SharedPreferences本身用于读取(getXXX(key,defvalue))数据。没有关于写数据的方法。
- SharedPreferences通过edit()方法获取Editor对象用于写入数据(putXXX(key,value))。
SharedPreferences是接口,无法直接创建,需通过Context的getSharedPreferences()方法获取。
@2 SharedPreferences使用解读
//定义
SharedPreferences sharedPreferences;
SharedPreferences.Editor edit;
//获取SharedPreferences,参数Context.MODE_PRIVATE表示该数据只能被本程序读写
sharedPreferences = getSharedPreferences("ags", Context.MODE_PRIVATE);
//写入数据
edit = sharedPreferences.edit();
edit.putFloat("floatValue",3.14f);
edit.putBoolean("BooleanValue",true);
edit.putString("StringValue","AGSTestStringValue");
edit.apply();//提交数据
//读取数据
float floatValue = sharedPreferences.getFloat("floatValue",0.0f);
Boolean boolValue = sharedPreferences.getBoolean("BooleanValue",false);
String stringValue = sharedPreferences.getString("StringValue","");
关于数据提交的说明:
- apply() 不会阻塞前台线程,后台提交修改。
- commit方法会阻塞前台线程但会立即生效。
@3 SharedPreferences存储路径
SharedPreferences数据存储在/data/data/<应用包名>/shared_prefs目录下,以xml格式保存,内容为键值对(key-value)。
@4 SharedPreferences官方文档
- SharedPreferences更详细解读参照文档:Android SharedPreferences类详解
- SharedPreferences.Editor更详细解读参照文档:Android SharedPreferences.Editor类详解
2 IO流 文件存储
2.1 APP内部文件存储
@1 文件存储基础
关于Android的文件存储,我们关注 打开/关闭、读/写,实际上和java原生的IO体系类似,尤其是读写,都是read/write。因此这里简述文件和文件夹的打开/关闭(主要针对APP内文件存储)。
@2 使用解读
关于文件,Context本身提供2个关键API(openFileOutput和openFileInput),使用如下所示:
//1 定义输入流
FileInputStream fileInputStream = null;
//打开操作,注意try catch
try {
//打开应用程序 数据文件夹下的test文件 输入流
fileInputStream = openFileInput("test");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
//关闭操作,注意try catch
if(fileInputStream!=null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//2 定义输出流
FileOutputStream fileOutputStream = null;
//打开操作,注意try catch
try {
//打开应用程序 数据文件夹下的test文件 输出流
//参数MODE_PRIVATE表示只能被当前程序读写,如果改为MODE_APPEND则表示追加内容
fileOutputStream = openFileOutput("test",MODE_PRIVATE);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
//关闭操作,注意try catch
if(fileOutputStream!=null){
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
关于文件夹,Context本身提供的关键API。使用如下所示:
//常见文件夹操作
File fileDir = getDir("dirtest",MODE_PRIVATE); //获取文件夹dirtest句柄
File fileDir2 = getFilesDir(); //获取应用程序 数据文件夹的绝对路径
String[] dir = fileList();//列出应用程序 数据文件夹下的 全部文件
deleteFile("filetest");//删除应用程序 数据文件夹下的 指定文件 filetest
//常见文件夹路径整理
getCacheDir().getAbsolutePath(); //路径 /data/user/0/<应用包名>/cache
getFilesDir().getAbsolutePath(); //路径 /data/user/0/<应用包名>/files
getExternalCacheDir().getAbsolutePath(); //路径 /storage/emulated/0/Android/data/<应用包名>/cache
getExternalFilesDir(null).getAbsolutePath(); //路径 /storage/emulated/0/Android/data/<应用包名>/files
@3 文件操作的权限
在SD卡上存储文件均需在AndroidManifest.xml文件中添加权限:
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@4 存储路径
数据存储在/data/data/<应用包名>/files 文件夹下。
@5 Context中 数据文件/文件夹 官方文档
注意:虽然很多文件操作 我们是通过Context来获取文件的相关API,但这些API实际上是定义在ContextWrapper类中的,详细解读如下:Android ContextWrapper类详解
2.2 APP外 文件存储
以上所涉及的是针对应用程序内数据文件/文件夹的相关操作。如果需要访问SD卡,则需要:
//获取SD卡目录的路径
String sdcardDir = Environment.getExternalStorageDirectory();
关于权限,如果需要创建/删除文件,那么还需要 挂载/卸载 权限(注意:系统APP),如下所示:
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
注意:在Android Q中该方法已被弃用,在Android Q之后不推荐使用该方法,如果要使用,需在权限之外 在 application节点中添加。
android:requestLegacyExternalStorage="true"
如果不使用该方法也可以,参照(引自 Android解决getExternalStorageDirectory在29后废弃问题)代码:
//通过APP所在路径 层层回滚到上级目录,直到Android,然后再拼接
File externalFileRootDir = getExternalFilesDir(null);
do {
externalFileRootDir = Objects.requireNonNull(externalFileRootDir).getParentFile();
} while (Objects.requireNonNull(externalFileRootDir).getAbsolutePath().contains("/Android"));
String saveDir = Objects.requireNonNull(externalFileRootDir).getAbsolutePath();
String savePath = saveDir + "/" + Environment.DIRECTORY_DCIM + "/" + filename;
3 数据库Sqlite简介(关键接口说明)
Android集成了轻量级Sqlite数据库,本质上是一种更加便捷的文件操作。关于这部分,首先回顾下数据库的基础知识:SQLite 简介 | 菜鸟教程。有了这个基础,加上本质上Android是对数据库Sqlite集成,因此该部分内容更依赖于对数据库的理解,该部分主要是对封装的关键类进行解读。
3.1 SQLiteDatabase类解读
SQLiteDatabase类既代表与数据库的连接,又可用于执行sql语句。相关操作整理如下:
//1 打开/创建数据库,从文件 或者 路径中读取数据库
/*flags解读:
*OPEN_READONLY :只读方式打开数据库(常量值为1)
*OPEN_READWRITE:读写方式打开数据库(常量值为0)
*CREATE_IF_NECESSARY:数据库不存在时创建数据库
*NO_LOCALIZED_COLLATORS:打开数据库时不根据本地化语言对数据库进行排序(常量值为:16)
*/
static SQLiteDatabase openOrCreateDatabase (File file,SQLiteDatabase.CursorFactory factory)
static SQLiteDatabase openDatabase(String path, SQLiteDatabase.CursorFactory factory, int flags, DatabaseErrorHandler errorHandler);
static SQLiteDatabase openDatabase(String path, SQLiteDatabase.CursorFactory factory, int flags);
static SQLiteDatabase openOrCreateDatabase(String path, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler);
static SQLiteDatabase openOrCreateDatabase(String path, SQLiteDatabase.CursorFactory factory);
//2 执行SQL语句
execSQL(String sql , Object[] args); //执行带占位符的sql语句
//Android考虑到有不熟悉sql语句的开发者,提供了进一步封装后的一系列方法,即:
long insert(String table,String nullColumnHack,ContentValues values);//插入记录
int delete(String table,String whereClause,String[] whereArgs);//删除一条记录
Cursor query(String table,String[] columns,String selection,String[] selectionArgs,String groupBy,String having,String orderBy);//查询一条记录
Cursor rawQuery (String sql,String[] selectionArgs,CancellationSignal cancellationSignal);//查询一条记录,sql语句模式
int update(String table,ContentValues values,String whereClause,String[] whereArgs);//修改记录
//事物开始/结束
beginTransaction();//开始事务
endTransaction(); //结束事务
inTransaction(); //处于事务上下文中,处于返回true,不处于返回false。
注意:rawQuery直接使用SQL语句进行查询,在第一个参数字符串内的“?”会被后面的String[]数组逐一对换掉;而query函数是Android自己封装的查询API,在实际使用场景中,query方法更不容易出错。
关于,更多详细内容查看官方文档:Android SQLiteDatabase类详解
3.2 SQLiteOpenHelper类解读
在真实的项目中更多的是使用工具类SQLiteOpenHelper来创建数据库 而不是使用SQLiteDatabase的openXXX方法来获取数据库的句柄(SQLiteOpenHelper是SQLiteDatabse的一个帮助类,用来管理数据的创建和版本更新,可以理解为对SQLiteDatabase的一种封装)。这里主要介绍SQLiteOpenHelper 打开数据库的方法。先定义一个子类,代码如下所示:
public class DbOpenHelper extends SQLiteOpenHelper {
public DbOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory,
int version) {
super(context, name, null, 1);
}
@Override //第1次创建时调用
public void onCreate(SQLiteDatabase db) {
}
@Override //数据库升级时自动调用
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
之后 使用该对象,如下所示:
//1 打开数据库
DbOpenHelper dbOpenHelper = new DbOpenHelper(MainActivity.this,"testDB",null,1);
//创建/打开 可读数据库
SQLiteDatabase sqLiteDatabaseR = dbOpenHelper.getReadableDatabase();
//创建/打开 可读写数据库
SQLiteDatabase sqLiteDatabaseRW = dbOpenHelper.getWritableDatabase();
//2 关于数据库操作:使用SQLiteDatabase的操作SQl的方式 或 封装的增删改查方法均可。
//3 关闭数据库,一次性关闭dbOpenHelper中所有的SQLiteDatabase类型句柄。
dbOpenHelper.close();
关于,更多详细内容查看官方文档:Android SQLiteOpenHelper类详解
3.3 Android的 sqlite3 命令
执行adb shell,进入到终端,然后执行:
$cd data/data/<project_name>/databases
$ls
列出数据库文件,接下来进入数据库,比如:
$sqlite3 test_db
显示如下内容:接下来可以对数据库进行命令行操作
SQLite version 3.6.22
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite>
常见sqlite3使用语句如下:
>.databases ----产看当前数据库
>.tables ----查看当前数据库中的表
>.help ----帮助信息,所有命令的解读