Android數據持久化,你還不會?
嘚吧嘚
數據持久化是開發過程中不可避免的,因爲數據是核心,是非常重要的。
總結一下常用的數據持久化的方式:
- SharedPreferences存儲數據
- 文件存儲數據
- SQLite數據庫存儲數據
- ContentProvider存儲數據
話不多說,上乾貨。
SharedPreferences(共享首選項)
適用範圍:
保存少量的數據,且這些數據的格式非常簡單(基本數據類型
)。比如應用程序的各種配置信息(如是否打開音效、是否使用震動效果、小遊戲的玩家積分等),解鎖口令密碼等
核心原理:
數據的保存形式是基於XML文件存儲的key-value鍵值對,通常用來存儲一些簡單的配置信息。通過DDMS的File Explorer面板,展開文件瀏覽樹,很明顯SharedPreferences數據總是存儲在/data/data//shared_prefs目錄下。SharedPreferences對象本身只能獲取數據而不支持存儲和修改,存儲和修改是通過SharedPreferences.edit()獲取的嵌入類Editor實現。
獲取首選項對象
SharedPreferences sp = getSharedPreferences(String name, int mode);
參數:
name: 首選項文件的名稱
mode: 首選項文件打開模式
MODE_PRIVATE 只能在本應用程序讀寫
MODE_WORLD_READABLE 能被其他應用讀
MODE_WORLD_WRITEABLE 能被其他應用讀寫
通過嵌入類Editor寫數據
//獲取嵌入類Editor
SharedPreferences.Editor edit = sp.edit();
//寫數據
edit.putXXXX(String key, value);
//提交
edit.commit();
切記,切記,寫完數據之後一定要提交,否則首選項文件不會保存數據
來看一下官方開發文檔中的介紹:
簡單翻譯一下:
提交從編輯首選項對象的編輯器返回的首選項文件中的改變(大體就是這個意思,若是翻譯的不好,大佬勿噴
🙈)
翻譯過來有點繞,斷一下句好理解一些了:
提交 / 從 / 編輯首選項對象的編輯器 / 返回的 / 首選項文件中的改變
不提交就不會保存數據的更改
從首選項文件獲取數據
SharedPreferences.getXXXX(String key, defaultvalue);
學以致用
layout佈局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
tools:context=".MainActivity">
<Button
android:id="@+id/msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="信息" />
</LinearLayout>
核心代碼:
/*
* 獲得 共享首選項對象(p1:文件名,p2:讀寫模式)
* 只有當前程序對test進行讀寫(test不存在時會自動創建)
*/
SharedPreferences sp = getSharedPreferences("test", MODE_PRIVATE);
/*
* 寫數據,通過嵌套類Editor寫數據
* 寫數據,保存在內存中沒有加入磁盤中
*/
SharedPreferences.Editor edit = sp.edit();
edit.putString("姓名", "張三");
edit.putInt("年齡", 21);
edit.putBoolean("性別", true);
//提交數據
edit.commit();
//讀取數據
String str = "姓名:" + sp.getString("姓名", "") +
",年齡:" + sp.getInt("年齡", 0) +
",性別:" + sp.getBoolean("性別", true);
Button msgBtn = findViewById(R.id.msg);
msgBtn.setOnClickListener((v) -> {
Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show();
});
效果圖:
文件存儲數據(File Java I/O)
將數據寫入文件
核心代碼
FileOutputStream fos = openFileOutput(fileName, mode);
fos.write(message.getBytes());
fos.close();
參數:
fileName: 數據待寫入的文件名稱
mode:文件打開模式
MODE_PRIVATE: 爲默認操作模式,代表該文件是私有數據,只能被應用本身訪問,在該模式下,寫入的內容會覆蓋原文件的內容,如果想把
新寫入的內容追加到原文件中。可以使用MODE_APPEND
MODE_APPEND: 模式會檢查文件是否存在,存在就往文件追加內容,否則就創建新文件。
MODE_WORLD_READABLE: 表示當前文件可以被其他應用讀取
MODE_WORLD_WRITEABLE: 表示當前文件可以被其他應用寫入
從文件中讀出數據
核心代碼
//fileName爲待讀取數據的文件的名稱
FileInputStream inStream = openFileInput(fileName);
byte[] buffer = new byte[1024];
int len = 0;
StringBuilder sb = new StringBuilder();
//從文件中讀取數據
while ((len = inStream.read(buffer)) != -1) {
sb.append(new String(buffer, 0, len));
}
//關閉輸入流
inStream.close();
//轉化爲字符串
str = sb.toString();
學以致用
首先將寫入數據和讀取數據的方法寫好。
/**
* 讀出文件中的數據
*
* @param fileName 文件的名稱
* @return 讀出的數據
*/
public String read(String fileName) {
try {
//創建一個FileInputStream對象
FileInputStream inStream = openFileInput(fileName);
byte[] buffer = new byte[1024];
int len = 0;
StringBuilder sb = new StringBuilder();
//從文件中讀取數據
while ((len = inStream.read(buffer)) != -1) {
sb.append(new String(buffer, 0, len));
}
//關閉輸入流
inStream.close();
return sb.toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 向文件中寫入數據
*
* @param message 待寫入的數據
* @param fileName 文件名稱
* @param mode 打開文件的模式
*/
public void write(String message, String fileName, int mode) {
//獲取輸入值
if (message == null)
return;
try {
//創建一個FileOutputStream對象,mode爲文件打開的模式
FileOutputStream fos = openFileOutput(fileName, mode);
//將獲取過來的值放入文件
fos.write(message.getBytes());
//關閉輸出流
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
layout佈局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="信息" />
<Button
android:id="@+id/info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="商店" />
</LinearLayout>
MainActivity主要代碼(實際開發中不能這麼寫,只作爲演示用
)
write("籃球:10個\n排球:5個\n羽毛球:6個\n", "message.txt", MODE_PRIVATE);
Button info = findViewById(R.id.info);
info.setOnClickListener((v) -> {
String read = read("message.txt");
Toast.makeText(MainActivity.this, read, Toast.LENGTH_SHORT).show();
});
效果圖:
SQLite數據庫存儲數據
SQLite是輕量級嵌入式數據庫引擎,它支持SQL語言,並且只利用很少的內存就有很好的性能。在我們爲移動設備開發應用程序時,也許就要使用到SQLite,所以我們就需要掌握移動設備上的SQLite開發技巧。
使用SQLite數據庫需要自定義一個類繼承SQLiteOpenHelper幫助類
來創建和升級數據庫。
提供一個簡單的模板,如下:
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast;
public class MyHelper extends SQLiteOpenHelper {
Context myContext;//上下文對象
/**
* @param context 上下文對象
* @param name 數據庫名稱
* @param factory 遊標工具類,用null
* @param version 數據庫版本,整數
*/
public MyHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
myContext = context;
}
//第一次創建數據庫時調用,如果數據庫已經存在,就不在調用
@Override
public void onCreate(SQLiteDatabase db) {
//創建一個學生表吧
String createTable = "create table student ("
+ "id integer primary key autoincrement,"
+ "sNumber text,"
+ "sName text,"
+ "sAge text)";
db.execSQL(createTable);//創建數據庫表
Toast.makeText(myContext, "學生表創建完畢!", Toast.LENGTH_LONG).show();
}
//數據庫版本變化時,會調用onUpgrade()
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//你的代碼
}
}
使用數據庫類SQLiteDatabase
對數據庫進行CRUD操作
僞代碼如下:
MyHelper helper = new MyHelper(MainActivity.this, "stud.db", null, 1);
SQLiteDatabase database = helper.getWritableDatabase();
//增 在數據庫例添加幾條數據
ContentValues values = new ContentValues();//ContentValue:封裝表中一行,用來添加或修改數據表
cv.put("sNumber","2018001");
cv.put("sName", "Tom");
cv.put("sAge", "21");
database.insert("student", null, cv);
cv.clear();
cv.put("sNumber","2018002");
cv.put("sName", "Tom");
cv.put("sAge", "22");
database.insert("student", null, cv);
cv.clear();
cv.put("sNumber","2018003");
cv.put("sName", "Tom");
cv.put("sAge", "19");
database.insert("student", null, cv);
cv.clear();
cv.put("sNumber","2018004");
cv.put("sName", "Jack");
cv.put("sAge", "21");
database.insert("student", null, cv);
cv.clear();
//刪 刪除名字叫“Tom”,年齡爲22歲的數據
int delete = database.delete("student", "sName = ? and sAge = ?", new String[]{"Tom", "22"});
System.out.println("res = " + delete);
//改 修改名字叫“Tom”,年齡爲21歲的數據,把名字修改爲“Tom2”
values.put("sName", "Tom2");//修改的數據
int update = database.update("student", values, "SName = ? and sAge = ?", new String[]{"Tom", "21"});
cv.clear();
System.out.println("res = " + update);
//查 查詢所有數據
Cursor stu = database.query("student", null, null, null, null, null, null);//Cursor:遊標類,封裝查詢結果
if (stu.moveToFirst()) {
do {
String sNumber = stu.getString(stu.getColumnIndex("sNumber"));
String sName = stu.getString(stu.getColumnIndex("sName"));
String sAge = stu.getString(stu.getColumnIndex("sAge"));
System.out.println("id:" + sNumber + "\t,name:" + sName + "\t,age:" + sAge);
} while (stu.moveToNext());
} else {
System.out.println("沒找到");
}
ContentProvider存儲數據
內容提供器(Content Provider)主要用於在不同的應用程序之間實現數據共享的功能,它提供了一套完整的機制,允許一個程序訪問另一個程序中的數據,不同於文件存儲和SharedPreferences存儲中的兩種全局可讀寫操作模式,內容提供器可以選擇只對哪一部分數據進行共享,從而保證我們程序中的隱私數據不會有泄漏的風險
詳細內容請參考文章《內容提供器ContentProvider》