安卓

Android数据存储的5种方式

2019-03-08  本文已影响0人  小的橘子

本文基于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

常用API

getFilesDir(); // 返回 /data/data/com.example.myapplication/files/  文件夹
fileList(); // 返回files/下的所有文件名字的数组
deleteFile(fileName); // 删除files/下 文件名为fileName的文件

总结

外部存储

外部存储指的是可移除的存储介质(例如 SD 卡)或内部(不可移除)存储.保存到外部存储的文件是全局可读取文件.外部存储用户是否在文件管理器中看到的. 存储分为两种:

  1. 应用卸载后,存储数据也会被删除
// 返回/storage/emulated/0/Android/data/com.example.myapplication/files
File externalFile = getExternalFilesDir(null);
Log.i(TAG, "onCreate:" + externalFile.getAbsolutePath());
  1. 永久存储,即使应用被卸载,存储的数据依然存在
// 返回如下路径 /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的使用

  1. 通过SQLiteOpenHelper帮助创建数据库
    • 创建该对象后并不会回调onCreate(),onOpen()方法。
    • 调用该对象的getWritableDatabase或getReadableDatabase()才会回调onCreate(),onOpen()方法。
      此时会在/data/data/com.nan.exer/databases路径下生成创建的db
  2. getWritableDatabase()和getReadableDatabase()区别
    两者均返回SQLiteDatabase对象,用来实现对数据库的操作
    • getWritableDatabase()
      以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,倘若使用的是getWritableDatabase() 方法就会出错。
    • getReadableDatabase()
      则是先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。如果该问题成功解决,则只读数据库对象就会关闭,然后返回一个可读写的数据库对象。
      ``

增删改查CRDU

方式一 执行sql语句

  1. 增删改
//将增删改的sql语句字符串直接通过db的execSQL()方法进行执行
db.execSQL(sql);
  1. 查询
    查询不能通过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语句

  1. 创建表
CREATE TABLE [IF NOT EXISTS] 表名(字段名称 数据类型 约束,...);
eg:CREATE TABLE IF NOT EXISTS contact(_id Integer primary key autoincrement,name text,phone_number text);
  1. 删除表
DROP TABLE [IF EXISTS] 表名;
DROP TABLE [IF EXISTS] contact;
  1. 插入数据
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")//指明列名
  1. 修改数据
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";表示对所有数据进行修改
  1. 删除数据
DELETE FROM 表名 WHERE 条件
eg:DELETE FROM contact where _id=1;//删除_id为1的行数据
eg:DELETE FROM contact;//删除所有行数据
  1. 查询数据
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会有哪些优化操作?

  1. 使用事务做批量操作,如上
  2. 及时关闭Cursor,避免内存泄漏
  3. 数据库操作较多建议子线程执行
  4. ContentValues容量调整:其内部采用HashMap存储键值数据,ContentValues初始容量为8,扩容时翻倍。因此建议对ContentValues填入的内容进行估量,设定合适的容量,减少不必要的扩容。

4. SQLite做批量操作有什么好方法吗?

使用SQLite的事务处理,由于默认SQLite开启事务处理,故每一条都包含事务,如果操作较多,大大影响性能。提升性能有如下两种方式:

  1. 手动开启事务,批量操作,提交事务 (性能提升幅度大)
  2. 使用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 对手机中数据库操作

  1. 进入程序的数据库位置(对于真机必须进行root才可以操作)
cd databases/
  1. 打开数据库
sqlite3 xxx.db
  1. 查看表格
.tables
  1. 查看帮助则看其他使用
.help
  1. 显示表头
// 该命在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作用

4. ContentProvider

5. 网络存储

上一篇下一篇

猜你喜欢

热点阅读