本文基于Android8.0验证
1. SharedPrefenece
存储路径/data/data/{包名}/shared_prefs/<文件名>
利用XML存储键值对,适合存储一些简单的配置信息.
2. 文件存储
从 Android 4.4 开始,读取或写入应用私有目录中的文件不再需要 READ_EXTERNAL_STORAGE 或 WRITE_EXTERNAL_STORAGE 权限。应用私有目录指的是/data/data/{packageName}/
和/storage/emulated/0/Android/data/{packageName}/
内部存储
/data/data/目录 ,对用户不可见
String FILENAME = "hello_file.txt";
String string = "hello world!";
FileOutputStream fos = null;
try {
//文件路径 /data/data/com.example.myapplication/files/
fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
openFileOutput还有其他Flag
- MODE_PRIVATE 私有数据,其他应用无法访问
- MODE_APPEND 文件已追加方式打开
- MODE_WORLD_WRITEABLE 所有应用可读,注意:已被废弃,在Android8.0已不能使用该属性
常用API
getFilesDir(); // 返回 /data/data/com.example.myapplication/files/ 文件夹
fileList(); // 返回files/下的所有文件名字的数组
deleteFile(fileName); // 删除files/下 文件名为fileName的文件
总结
- openFileOutput()的方法写入文件路径在
/data/data/com.example.myapplication/files/
下 -
data/{pakcage}/
在应用卸载后会清除
外部存储
外部存储指的是可移除的存储介质(例如 SD 卡)或内部(不可移除)存储.保存到外部存储的文件是全局可读取文件.外部存储用户是否在文件管理器中看到的. 存储分为两种:
- 应用卸载后,存储数据也会被删除
// 返回/storage/emulated/0/Android/data/com.example.myapplication/files
File externalFile = getExternalFilesDir(null);
Log.i(TAG, "onCreate:" + externalFile.getAbsolutePath());
- 除了getExternalFilesDir()之外,还有getExternalCacheDir(),文件将保存到/storage/emulated/0/Android/data/{packageName}/cache目录下,当文件不再需要时,记得把缓存文件删除。
- 该部分也属于程序私有目录,故无需读写权限
- 永久存储,即使应用被卸载,存储的数据依然存在
// 返回如下路径 /storage/emulated/0
File externalStoreage = Environment.getExternalStorageDirectory();
String externalStoragePath = externalStoreage.getAbsolutePath();
String directory = externalStoragePath + "/hello.txt";
// directory输出为/storage/emulated/0/hello.txt
Log.i(TAG, "onCreate: directory=" + directory);
try {
FileOutputStream fos = new FileOutputStream(directory);
// 需要动态存储权限
fos.write("helloworld".getBytes());
} catch (Exception e) {
e.printStackTrace();
}
上面代码生成的文件在手机的文件管理器下点击Internal shared storeage进去,就可看到hello.txt
3. SQLite存储
SQLite与大型数据库的区别
两者都是支持关系的关系型数据库,SQLite是一个嵌入型的轻量级数据库,适合小数据量,大型数据库独立运行在数据库服务器上,适合大数据量级别,大型数据库通常以网络的方式对外提供服务。
SQLite的使用
- 通过SQLiteOpenHelper帮助创建数据库
- 创建该对象后并不会回调onCreate(),onOpen()方法。
- 调用该对象的getWritableDatabase或getReadableDatabase()才会回调onCreate(),onOpen()方法。
此时会在/data/data/com.nan.exer/databases路径下生成创建的db
- getWritableDatabase()和getReadableDatabase()区别
两者均返回SQLiteDatabase对象,用来实现对数据库的操作- getWritableDatabase()
以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,倘若使用的是getWritableDatabase() 方法就会出错。 - getReadableDatabase()
则是先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。如果该问题成功解决,则只读数据库对象就会关闭,然后返回一个可读写的数据库对象。
``
- getWritableDatabase()
增删改查CRDU
方式一 执行sql语句
- 增删改
//将增删改的sql语句字符串直接通过db的execSQL()方法进行执行
db.execSQL(sql);
- 查询
查询不能通过execSQL(sql)来执行
//通过rawQuery方法实现原始sql的执行,第二个参数为查询的条件,执行完返回Cursor对象
db.rawQuery(sql,null);
方式二 使用Android封装好的api实现
我们只需要传入指定的参数即可,底层会将参数拼接成sql语句执行
// 增删改查对应方法
db.insert();
db.delete();
db.update();
db.query();
SQLite数据库升级
一、软件v1.0
安装v1.0,假设v1.0版本只有一个account表,这时走继承SQLiteOpenHelper的onCreate,不走onUpgrade。
1、v1.0(直接安装v1.0)
二、软件v2.0
有2种安装软件情况:
1、v1.0 --> v2.0 不走onCreate,走onUpgrade
2、v2.0(直接安装v2.0) 走onCreate,不走onUpgrade
v1.0版本只有一个account表,软件版本升级到v2.0了,但是v2.0数据库需要新增一个member表,那怎么办呢?这里有2种情况了:一种是安装了v1.0升级到v2.0,这时不会走继承SQLiteOpenHelper的onCreate,而是直接走onUpgrade,这时就要在onUpgrade添加member表的代码了,在onCreate加了也没用,因为这种情况都不走onCreate。。另一种情况就是用户从来没有安装过这个软件,直接安装v2.0,这时走继承SQLiteOpenHelper的onCreate,不走onUpgrade,所以要在onCreate添加member表的代码。这怎么办呢?这就要合理升级数据库版本了。
三、软件v3.0
假设v3.0又新增一个news表,这里有三种情况:
1、v1.0 --> v3.0 不走onCreate,走onUpgrade
2、v2.0 --> v3.0 不走onCreate,走onUpgrade
3、v3.0(直接安装v3.0) 走onCreate,不走onUpgrade
SQLite3 sql语句
- 创建表
CREATE TABLE [IF NOT EXISTS] 表名(字段名称 数据类型 约束,...);
eg:CREATE TABLE IF NOT EXISTS contact(_id Integer primary key autoincrement,name text,phone_number text);
- 删除表
DROP TABLE [IF EXISTS] 表名;
DROP TABLE [IF EXISTS] contact;
- 插入数据
INSERT INTO 表名[字段1,字段2] values(values1,values2,...);
eg:INSERT INTO contact VALUES(2,"wyn","110")//常用,必须从表的第一列到最后一列进行赋值
eg:INSERT INTO contact(name,phone_number) VALUES("nan","111")//指明列名
- 修改数据
UPDATE 表名 set 字段1=新值,字段2=新值 WHERE 条件
eg:UPDATE contact SET name="hello",phone_number="10086" WHERE _id=1;
eg:UPDATE contact SET name="hello",phone_number="10086";表示对所有数据进行修改
- 删除数据
DELETE FROM 表名 WHERE 条件
eg:DELETE FROM contact where _id=1;//删除_id为1的行数据
eg:DELETE FROM contact;//删除所有行数据
- 查询数据
SELECT 字段名 FROM 表名 WHERE 查询条件 GROUP BY 分组的字段 HAVING 筛选条件 ORDER BY 排序字段//GROUP BY,HAVING不常用
eg:SELECT * FROM contact;
SELECT * FROM contact WHERE _id=1;
SELECT * FROM contact WHERE _id<>1;//_id不等于1
SELECT * FROM contact WHERE _id=1 AND age>18;//与的意思
SELECT * FROM contact WHERE name LIKE "%好%";//含有好的所有字符串
SELECT * FROM contact WHERE name LIKE "_好%";//好前面只有一个字符的所有字符串
SELECT * FROM contact WHERE name IS NULL;
SELECT * FROM contact WHERE age BETWEEN 10 AND 20;//age在10到20之间的
SELECT * FROM contact WHERE age>20 ORDER BY _id;//_id进行排序
面试相关
1. SQLite中事务处理是如何做的
SQLite在做CRDU是默认开启了事务,然后把SQL语句最终交由SQLiteStatement并调用相应的CRDU方法,此时整个操作还在db-journal这个临时文件上进行,只有顺利完成才会更新.db数据库,否则就会被回滚。
2. 删除SQLite中表一个字段如何做?
SQLite数据库只允许添加表字段而不允许删除和修改表字段,只能采取复制思想,即创建一个表包含想要的字段,再将数据复制到该表中,最后删除旧表。
3. 使用SQLite会有哪些优化操作?
- 使用事务做批量操作,如上
- 及时关闭Cursor,避免内存泄漏
- 数据库操作较多建议子线程执行
- ContentValues容量调整:其内部采用HashMap存储键值数据,ContentValues初始容量为8,扩容时翻倍。因此建议对ContentValues填入的内容进行估量,设定合适的容量,减少不必要的扩容。
4. SQLite做批量操作有什么好方法吗?
使用SQLite的事务处理,由于默认SQLite开启事务处理,故每一条都包含事务,如果操作较多,大大影响性能。提升性能有如下两种方式:
- 手动开启事务,批量操作,提交事务 (性能提升幅度大)
- 使用db.compileStatement返回的SQLiteStatement进行sql语句操作(性能提升小)
实例如下
String sql = "INSERT INTO table (number, nick) VALUES (?, ?)";
// 1. 开启事务
db.beginTransaction();
// 2. 通过SQLiteStatement操作
SQLiteStatement stmt = db.compileStatement(sql);
for (int i = 0; i < values.size(); i++) {
stmt.bindString(1, values.get(i).number);
stmt.bindString(2, values.get(i).nick);
stmt.execute();
stmt.clearBindings();
}
db.setTransactionSuccessful();
// 3. 结束事务
db.endTransaction();
SettingsProvider中DatabaseHelper就是采用该种方式
SQLite3使用
Sqlite3 对手机中数据库操作
- 进入程序的数据库位置(对于真机必须进行root才可以操作)
cd databases/
- 打开数据库
sqlite3 xxx.db
- 查看表格
.tables
- 查看帮助则看其他使用
.help
- 显示表头
// 该命在sqlite3 打开数据库后执行
1. ".header on" 启用表头
2. ".mode column" 使用列模式
sqlite3 : not found 问题
原因:
system/xbin/目录下不存在sqlite3的执行文件
解决
1. adb pull system/xbin/sqlite3 //对存在该文件的手机中操作
2. adb remount //目标机器
3. adb push sqlite3 system/xbin/ //文件权限需要和源文件保持一致
db-journal作用
- 该文件是临时文件,用于事务的回滚。事务开始时产生,事务结束时删除。当事务开始时掉电,db-journal文件就会保存在磁盘上,再次开机则可用于事务回滚。
- 在Android上,该文件不会删除,当没有事务时该文件大小为0,存在事务时则该文件用于事务回滚。
网友评论