01. 持久化简介
- 瞬时数据就是指那些存储在内存当中,有可能会因为程序关闭或其他原因导致内存被回收而丢失的数据。
- 持久化数据就是指将那些内存中的瞬时数据保存到存储设备中,保证即使在手机或电脑关机的情况下,这些数据仍然不会丢失。
02. 文件存储
文件存储不对存储的内容进行任何的格式化处理,所有数据都是原封不动地保存到文件当中。因而比较适合用于存储一些简单的文本数据或二进制数据。
通过
Context
提供的openFileOutput()
方法将文件存入内部存储路径中。操作模式Context.MODE_PRIVATE
默认模式私有且覆盖Context.MODE_APPEND
模式每次写入数据进行追加
通过
Context
提供的openFileInput()
方法用于从文件中进行数据读取。存数据
/** * 保存数据到内部存储文件 * * @param fileName 文件名称 * @param saveData 写入的数据 */ private void saveToFile(String fileName, String saveData) { FileOutputStream fileOutputStream = null; BufferedWriter bufferedWriter = null; try { fileOutputStream = this.openFileOutput(fileName, Context.MODE_APPEND);// [/data/data/com.just.first/files] bufferedWriter = new BufferedWriter(new OutputStreamWriter(fileOutputStream)); bufferedWriter.write(saveData); } catch (IOException e) { e.printStackTrace(); } finally { try { if (bufferedWriter != null) { bufferedWriter.close(); } if (fileOutputStream != null) { fileOutputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } }
取数据
/** * 从内部存储文件中读取数据 * * @param fileName 文件名称 * @return 文件内容 */ private String loadFromFile(String fileName) { FileInputStream fileInputStream = null; BufferedReader bufferedReader = null; StringBuilder dataContent = new StringBuilder(); try { fileInputStream = this.openFileInput(fileName); bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream)); String line = ""; while ((line = bufferedReader.readLine()) != null) { dataContent.append(line); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (bufferedReader != null) { bufferedReader.close(); } if (fileInputStream != null) { fileInputStream.close(); } } catch (IOException e) { e.printStackTrace(); } } return dataContent.toString(); }
03. SharedPreferences
SharedPreferences
使用键值对的方式存储数据。支持多种
不同的数据类型
存储。文件存储路径
/data/data/主包名/shared_prefs
文件存储的是
xml
文件。获取
sharedPreferences
实例的三种方法- 通过
Context
类的getSharedPreferences(String name, int mode)
方法获取。
- 第一个参数文件名称
- 第二个参数模式
- 通过
Activity
类的getPreferences(int mode)
方法获取。
- 一个参数模式
- 文件名称会自动获取当前活动类名
getLocalClassName()
- 通过
PreferenceManager
类的getDefaultSharedPreferences(Context context)
方法获取。
- 一个参数上下文
- 文件名称会自动获取当前程序主包名
context.getPackageName() + "_preferences"
- 通过
存储数据需要三个步骤
- 获取
SharedPreferences.Editor
对象 - 通过
Editor
对象进行数据的添加 - 调用
Editor
的apply()
方法进行数据的提交
- 获取
存数据
/** * 将数据保存到 SharedPreferences * * @param fileName 文件名 * @param keyWord 键 * @param saveData 值 */ private void saveToSharedPreferences(String fileName, String keyWord, String saveData) { SharedPreferences sharedPreferences = this.getSharedPreferences(fileName, MODE_APPEND); SharedPreferences.Editor edit = sharedPreferences.edit(); edit.putString(keyWord, saveData); edit.apply(); }
取数据
/** * 从 SharedPreferences 加载数据 * * @param fileName 文件名 * @param keyWord 键 * @return 值 */ private String loadFromSharedPreferences(String fileName, String keyWord) { SharedPreferences sharedPreferences = this.getSharedPreferences(fileName, MODE_APPEND); return sharedPreferences.getString(keyWord, null);// 默认值 }
数据的写入和读取均可以根据类型进行操作。
04. SQLite 数据库
SQLite
数据库是一款轻量级的关系型数据库,运算速度快,占用资源少。支持标准 SQL 语法,遵循数据库的 ACID 事务。自定义
SQLiteOpenHelper
继承系统SQLiteOpenHelper
/** * SQLiteOpenHelper 实现数据库创建与升级 * * @author JustDo23 */ public class BookOpenHelper extends SQLiteOpenHelper { /** * 构造方法[必须实现] * * @param context 上下文 * @param name 数据库名称[带上后缀 .db] * @param factory 工厂[允许数据查询使用自定义 Cursor][一般传 null] * @param version 版本[整型] */ public BookOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, "BookStore" + ".db", null, 1); } /** * 创建数据表方法[必须实现] * * @param db 数据库操作对象 */ @Override public void onCreate(SQLiteDatabase db) { String sql = "create table Book ( " + "id integer primary key autoincrement" + ", " + "author text" + ", " + "price real" + ", " + "pages integer" + ", " + "name text" + ")"; db.execSQL(sql);// 执行 SQL 语句 } /** * 数据库升级方法[必须实现] * * @param db 数据库操作对象 * @param oldVersion 旧的版本号 * @param newVersion 新的版本号 */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
数据库文件存储路径
/data/data/主包名/databases
注意:
SQL 语句中相应位置的空格及分割符很重要数据类型
integer
表示整型real
表示浮点型text
表示文本类型blob
表示二进制类型primary key
表示主键autoincrement
表示自增长
数据库的创建
- 继承系统
SQLiteOpenHelper
并实现相应方法后并没有实现数据库的创建 - 在
SQLiteOpenHelper
中有两个重要的方法
getReadableDatabase()
获取读数据操作的对象getWritableDatabase()
获取写数据操作的对象- 这两个方法可以创建或打开一个数据库。数据库存在则直接打开,数据库不存在则创建并打开。
- 这两个方法返回的对象都可以对数据库进行读写操作。
- 当数据不可写入时候如磁盘空间已满,
getReadableDatabase()
方法将以只读方式打开数据库,getWritableDatabase()
方法会抛出异常。
- 继承系统
ADB 调试工具
进入 Shell 内核
$ adb shell
打开数据库
$ sqlite3 BookStore.db
查看数据库中的数据表
$ .table
- 数据表
android_metadata
是每个数据库自动生成的
- 数据表
查看建表语句
$ .schema
退出
$ .exit $ .quit
05. 数据库操作
升级数据库
/** * 数据库升级方法 */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { db.execSQL("drop table if exists Book");// 删除原来的表 onCreate(db);// 重新进行创建 }
- 先将已经存在的数据表进行删除,然后创建新的表。数据表不能重复创建,否则会崩溃。
- 修改构造方法中的数据库版本号。
概述
数据库操作有 4 种简称
CRUD
C
代表Create
添加insert
R
代表Retrieve
查询select
U
代表Update
更新update
D
代表Delete
删除delete
添加数据
- 利用
SQLiteDatabase
对象的insert(String table, String nullColumnHack, ContentValues values)
方法进行数据数据添加 - 第一个参数表名
- 第二个参数用于在未指定添加数据的情况下给某些可为空的列自动赋值 NULL 一般传入 null 即可
第三个参数数据集合键值对关系键为列名因此值为数据
public void insert() { SQLiteDatabase writableDatabase = bookOpenHelper.getWritableDatabase();// 获取数据操作对象 ContentValues contentValues = new ContentValues();// 键值对集合 contentValues.put("name", "FirstLine");// 列名-数据 contentValues.put("author", "Guo"); contentValues.put("pages", "570"); contentValues.put("price", 79.0); writableDatabase.insert("Book", null, contentValues);// 指定表名添加 }
数据库的查询语句
$ select * from Book;
- 利用
更新数据
- 利用
SQLiteDatabase
对象的update(String table, ContentValues values, String whereClause, String[] whereArgs)
方法进行数据数据更新 - 后两个参数用于约束更新某一行或者某几行的数据,不指定默认更新所有行。
- 第三个参数对应 SQL 语句的 where 部分其中
?
代表占位符 第四个参数按照先后顺序对应为占位符进行赋值
public void update() { SQLiteDatabase writableDatabase = bookOpenHelper.getWritableDatabase();// 获取数据操作对象 ContentValues contentValues = new ContentValues();// 键值对集合 contentValues.put("price", 99.9); writableDatabase.update("Book", contentValues, "name = ?", new String[]{"FirstLine"}); }
- 利用
删除数据
利用
SQLiteDatabase
对象的delete(String table, String whereClause, String[] whereArgs)
方法进行数据数据删除public void delete() { SQLiteDatabase writableDatabase = bookOpenHelper.getWritableDatabase();// 获取数据操作对象 writableDatabase.delete("Book", "name = ?", new String[]{"FirstLine"}); }
查询数据
SQL
的全称是Structured Query Language
即结构化查询语言
- 利用
SQLiteDatabase
对象的query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy)
方法进行数据数据查询 query()
重载函数比较多功能与 SQL 语句中的查询类似
query方法参数 对应 SQL 部分 描述 table from table_name 指定查询的表名 columns select column1, column2 指定查询的列名 selection where column = value 指定 where 的约束条件 selectionArgs - 为 where 中的占位符提供具体的值 groupBy group by column 指定需要 group by 的列 having having column = value 对 group by 后的结果进一步约束 orderBy order by column1, column2 指定查询结果的排序方式 不需要的参数可以指定为 null
public void query() { SQLiteDatabase readableDatabase = bookOpenHelper.getReadableDatabase();// 获取数据操作对象 Cursor cursor = readableDatabase.query("Book", null, null, null, null, null, null);// 查询获得游标 if (cursor.moveToFirst()) {// 是否可以移动位置 do { String author = cursor.getString(cursor.getColumnIndex("author")); String name = cursor.getString(cursor.getColumnIndex("name")); String pages = cursor.getString(cursor.getColumnIndex("pages")); String price = cursor.getString(cursor.getColumnIndex("price")); LogUtils.e("Book: " + author + " -- " + name + " -- " + pages + " -- " + price); } while (cursor.moveToNext());// 是否可以继续往下移动 } }
使用 SQL 语句
添加数据
writableDatabase.execSQL("insert into Book (name, author, pages, price) values (?, ?, ?, ?)", new String[]{"SecondLine", "Lin", "123", "66.6"});writableDatabase.execSQL("insert into Book (name, author, pages, price) values (?, ?, ?, ?)", new String[]{"SecondLine", "Lin", "123", "66.6"});
更新数据
writableDatabase.execSQL("update Book set pages = ? where author = ?", new String[]{"333", "Lin"});writableDatabase.execSQL("update Book set pages = ? where author = ?", new String[]{"333", "Lin"});
删除数据
writableDatabase.execSQL("delete from Book where pages > ?", new String[]{"10"});
查询数据
readableDatabase.rawQuery("select * from Book", null);// 查询获得游标
06. LitePal 数据库
LitePal 采用了对象关系映射 ORM 的模式。简单说,我们使用的编程语言是面向对象语言,而使用的数据库则是关系型数据库,那么将面向对象的语言和面向关系的数据库之间建立一种映射关系,这就是对象关系映射了。因此,可以用面向对象的思维来操作数据库,而不用再和 SQL 语句打交道。
使用步骤
- 添加依赖
- 创建
assets
文件夹 - 创建
litepal.xml
配置文件 - 在
Application
中进行初始化 - 创建实体类也就是表结构
- 配置
litepal.xml
文件
创建数据库
LitePal.getDatabase();// 使用 LitePal 创建数据库
添加数据
- 实体类需要要继承
DataSupport
类 直接调用实体类的
save()
方法Book book = new Book();// 实例化实体类 book.save();// 使用 LitePal 插入数据
- 实体类需要要继承
更新数据
- 通过对已存储的对象重新设值后重新调用
save()
方法来更新。 调用
model.isSaved()
方法返回true
则表示已存储的对象。一种是调用过save()
方法的对象,一种是通过LitePal
的查询 API
得到的对象。Book book = new Book();// 实例化实体类 book.save();// 使用 LitePal 插入数据 book.setPages("324");// 更新数据 book.save();// 对插入的数据进行更新
通过任意对象设置需要更新的值后调用
updateAll(String... conditions)
方法来更新- 第一个参数可以指定条件约束,不指定代表更新所有
注意:
将某个字段设置为默认值需要调用setToDefault(String fieldName)
参数字段名Book book = new Book();// 实例化实体类 book.setPages("776");// 更新数据 book.setToDefault("price");// 设置默认值 book.updateAll("name = ? and pages = ?", "老人与海", "76");
- 通过对已存储的对象重新设值后重新调用
删除数据
- 通过调用已存储的对象的
delete()
方法来删除 直接使用
DataSupport.deleteAll()
传递参数进行删除,传递表名及约束,不传则删除所有DataSupport.deleteAll(Book.class, "pages < ?", "400");// 指定表名及约束进行删除
- 通过调用已存储的对象的
查询数据
- 直接使用
DataSupport
类中的相关方法进行查询 查询所有
DataSupport.findAll(Book.class);// 查询所有 DataSupport.findFirst(Book.class);// 查询第一条 DataSupport.findLast(Book.class);// 查询最后一条
更多查询功能
DataSupport.select("name", "author", "pages")// 指定查询的列 .where("pages > ?", "400")// 指定查询的约束条件 .order("pages desc")// 指定查询结果排序 .limit(10)// 指定查询结果数量 .offset(2)// 指定查询结果偏移-抛弃前2条 .find(Book.class);// 指定查询的表名
select()
方法用于指定查询哪几列的数据where()
方法用于指定查询的约束条件order()
方法用于指定查询结果的排序方式 另desc
表示降序asc
表示升序limit()
方法用于指定查询结果的数量offset()
方法用于指定查询结果偏移量
- 直接使用
07. 小结
- 文件存储核心是
Java
中的I/O 流操作
因此需要进行复习练习。 - 注意
SharedPreferences
提交apply()
方法与commit()
方法。 - 数据库的原生 API 使用及一些第三方库的使用。
- 数据库操作对象及游标对象等在使用结束后一定要进行关闭。