Android資料儲存的方式
1.Android常用的資料儲存方式
- File儲存
- SharedPreferences儲存
- SQLite輕量型資料庫
- ContentProvider 四大元件之一
2.File儲存
最基本的一種資料儲存方式,不對儲存的內容進行任何的格式化處理,所有資料都是原封不動的儲存到檔案中,適合儲存一些簡單的文字資料或二進位制資料。儲存的資料位於/data/data/< package name>/files/
目錄下
Context類中提供了2種常用方法:
-
openFileOutput(“fileName”,mode)開啟檔案輸出流,從程式種寫入到指定檔案
第一個引數代表檔名稱,不能包含路徑。第一個為檔案的操作模式:Context.MODE_PRIVATE 預設操作模式,檔案存在時覆蓋檔案的內容 Context.MODE_APPEND 檔案已存在,內容追加。不存在則自動建立新檔案 Context.MODE_WORLD_READABLE 允許其他程式進行讀操作 Context.MODE_WORLD_WRITEABLE 允許其他程式進行讀寫操作
後兩種模式在4.2後已被廢棄
- openFileInput(“fileName”)開啟檔案輸入流,從檔案種讀取檔案並讀取到程式
- getDir(String name,int mode)在應用程式的資料資料夾下獲取或建立name對應的子目錄
- getFilesDir() 資料資料夾的絕對路徑
- fileList() 資料資料夾下的全部檔案
- deleteFile(String) 刪除資料資料夾下指定檔案
封裝的工具類:
package com.wdl.crazyandroiddemo; import android.content.Context; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; /** * author: wdl * time: 2018/11/13 20:52 * des: File方式讀寫檔案,工具類 */ public class FileWRTool { /** * 輸出流形式,來儲存檔案 * * @param context 上下文 * @param fileName 檔名 * @param data 要儲存的字串 * fileName 是要要生成的檔案的檔名(data.txt) */ public static void writeFile(Context context, String fileName, String data) { FileOutputStream outputStream; BufferedWriter bufferedWriter = null; try { outputStream = context.openFileOutput(fileName, Context.MODE_PRIVATE); bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream)); bufferedWriter.write(data); } catch (IOException e) { e.printStackTrace(); } finally { if (bufferedWriter != null) try { bufferedWriter.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * 輸入流形式,來讀取fileName檔案 * * @param context 上下文 * @param fileName 檔名 * @return 檔案內容 */ public static String readFile(Context context, String fileName) { //位元組輸入流 FileInputStream inputStream; //緩衝流 BufferedReader bufferedReader = null; StringBuilder stringBuffer = new StringBuilder(); try { inputStream = context.openFileInput(fileName); bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); String line; while ((line = bufferedReader.readLine()) != null) { stringBuffer.append(line); } } catch (IOException e) { e.printStackTrace(); } finally { if (bufferedReader != null) { try { bufferedReader.close(); } catch (IOException e) { e.printStackTrace(); } } } return stringBuffer.toString(); } }
3.SharedPreferences儲存
用於儲存少量資料,資料格式較為簡單,使用鍵值對進行儲存。比如:應用程式的各種配置資訊等。具有一定的快取機制,併發讀寫可能會導致不可預知的結果。儲存於/data/data/< package name>/shared_prefs/name
格式:
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
<string name="name">wdl</string>
<long name="price" value="23" />
<int name="age" value="23" />
<boolean name="man" value="true" />
</map>
使用方法:
-
第一步:獲取例項
SharedPreferences是一個介面,無法直接建立SharedPreferences例項。
A:通過Context.getSharedPreferences(String name,int mode)獲取例項Name:檔名 mode:
1.Context.MODE_PRIVATE 只能被本應用讀寫
2.Context.MODE_WORLD_READABLE 可被其他程式讀,不可寫
3.Context.MODE_WORLD_WRITEABLE 可被其他程式讀寫 4.2後捨棄
B:Activity類中的getPreferences(int mode)方法獲取
與第一種方法類似,以當前活動類名作為檔名稱
C:PreferenceManager類中的getDefaultSharedPreferences(Context context)方法獲取使用當前應用程式包名作為字首來命名檔案
-
第二步:獲取SharedPreferences.Editor物件,Edit = sp.edit();
-
第三步:edit.putXXX(key,value)新增 edit.remove(key) edit.clear()等
-
第四步:edit.commit() edit.apply()
工具類:
package com.wdl.crazyandroiddemo;
import android.content.Context;
import android.content.SharedPreferences;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
/**
* author: wdl
* time: 2018/11/14 14:46
* des: SharedPreferences工具類
*/
@SuppressWarnings("unused")
public class AppSharedUtil {
//檔名
private static final String FILE_NAME = "share_pref";
/**
* 根據傳入的object按照對應方法寫入檔案
*
* @param context 上下文
* @param key key
* @param object 值
*/
public static void put(Context context, String key, Object object) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
if (object instanceof Integer) {
editor.putInt(key, (Integer) object);
} else if (object instanceof String) {
editor.putString(key, (String) object);
} else if (object instanceof Float) {
editor.putFloat(key, (Float) object);
} else if (object instanceof Long) {
editor.putLong(key, (Long) object);
} else if (object instanceof Boolean) {
editor.putBoolean(key, (Boolean) object);
}
SharedPreferencesCompat.apply(editor);
}
/**
* 根據key與defaultValue獲取對應的值
*
* @param context 上下文
* @param key key
* @param defaultValue 預設值
* @return Object
*/
public static Object get(Context context, String key, Object defaultValue) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
if (defaultValue instanceof String) {
return sp.getString(key, (String) defaultValue);
} else if (defaultValue instanceof Integer) {
return sp.getInt(key, (Integer) defaultValue);
} else if (defaultValue instanceof Boolean) {
return sp.getBoolean(key, (Boolean) defaultValue);
} else if (defaultValue instanceof Float) {
return sp.getFloat(key, (Float) defaultValue);
} else if (defaultValue instanceof Long) {
return sp.getLong(key, (Long) defaultValue);
}
return null;
}
/**
* 刪除對應key的值
*
* @param context 上下文
* @param key key
*/
public static void remove(Context context, String key) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.remove(key);
SharedPreferencesCompat.apply(editor);
}
/**
* 是否包含指定key
*
* @param context 上下文
* @param key key
* @return boolean
*/
public static boolean contains(Context context, String key) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
return sp.contains(key);
}
/**
* 清空
*
* @param context Context
*/
public static void clear(Context context) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.clear();
SharedPreferencesCompat.apply(editor);
}
/**
* 獲取所有
*
* @param context Context
* @return map
*/
public static Map<String, ?> getAll(Context context) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
return sp.getAll();
}
/**
*
*/
private static class SharedPreferencesCompat {
private static final Method applyMethod = findApplyMethod();
/**
* 反射查詢apply方法
*
* @return Method
*/
private static Method findApplyMethod() {
try {
Class<?> clazz = SharedPreferences.Editor.class;
return clazz.getMethod("apply");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
/**
* apply存在則使用apply,否則使用commit
*
* @param editor SharedPreferences.Editor
*/
private static void apply(SharedPreferences.Editor editor) {
if (applyMethod != null) {
try {
applyMethod.invoke(editor);
return;
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
editor.commit();
}
}
}
因為commit方法是同步的,並且我們很多時候的commit操作都是UI執行緒中,畢竟是IO操作,儘可能非同步;
所以我們使用apply進行替代,apply非同步的進行寫入。
4.SQLite輕量型資料庫
Android系統內建了資料庫,SQLite是一款輕量級的關係型資料庫,運算速度快,佔用記憶體小。SQLite支援標準的SQL語法,遵循了資料庫的ACID事務。SQLite資料庫只是一個檔案。
Android提供SQLiteDatabase代表一個數據庫,提供以下靜態方法開啟對應的資料庫:
- openDatabase(String path,SQLiteDatabase.CursorFactory factory,int flags) 開啟path檔案所代表的SQLite資料庫
- openOrCreateDatabase(File file,CursorFactory factory)開啟或(如果不存在)建立file檔案所代表的SQLite資料庫
- openOrCreateDatabase(String path,SQLiteDatabase.CursorFactory factory)開啟或(如果不存在)建立path檔案所代表的SQLite資料庫
獲取SQLiteDatabase物件後,呼叫如下方法來操作資料庫:
4. execSQL(String sql,Object[] bindArgs)
執行帶佔位符的SQL語句
5. execSQL(String sql)
執行SQL語句
6. beginTransaction()
開始事務
7. endTransaction()
結束事務
8. rawQuery(String sql,String[] selectionArgs)
執行帶佔位符的SQL查詢
9. insert(String table,String nullColumnHack,ContentValues values)
向指定表插入資料;nullColumnHack代表強行插入null值的資料列名
10. update(String table,ContentValues values,String whereClause,String[] whereArgs)
更新表中的特定資料;whereClause限定的條件;whereArgs引數值
11. delete(String table,String whereClause,String[] whereArgs)
刪除指定表中的特定資料
12. Cursor query(boolean distinct,String table,String[] columns,String whereClause,String[] whereArgs,String groupBy,String having,String orderBy,String limit)
指定資料表進行查詢,distinct是否重複;table表名;columns列名;whereClause 條件語句(帶佔位符);whereArgs引數;groupBy分組;having約束;orderBy排序;limit限制條數
查詢方法返回的都是一個Cursor,相當於JDBC的ResultSet,提供如下方法:
- moveToFirst() 將指標移到第一行,成功返回true
- moveToLast() 將指標移到最後一行,成功返回true
- moveToNext()將指標移到下一行,成功返回true
- moveToPosition(int position)將指標移到指定行
- moveToPrevious() 將指標移到上一行,成功返回true
Sqlite3常用指令:
-
.databases 檢視當前資料庫
-
.tables 檢視所有表
-
.help 檢視支援的命令
特點:內部只支援NULL,INTEGER,REAL,TEXT,BLOB,實際可接受varchar,char,decimal等資料型別,運算或儲存時將它們轉換為以上的型別。允許把各種型別的資料儲存到任何型別欄位中.
事務
- beginTransaction() 開始事務
- endTransaction() 結束事務
- inTransaction() 判斷是否處於事務環境中
注意:
當程式執行endTransaction() 方法時會結束事務,那到底是提交事務還是回滾事務,取決於SQLiteDatabase是否呼叫了setTransactionSuccessful()設定事務標誌,如果設定則提交,否則則回滾事務。
SQLiteOpenHleper類
專案中通常繼承SQLiteOpenHleper類開發子類,通過如下方法:
- synchronized SQLiteDatabase getReadableDatabase() 以讀寫的方式開啟對應資料庫,磁碟滿 只讀
- synchronized SQLiteDatabase getWriteableDatabase()以寫的方式開啟對應資料庫,磁碟滿會出錯
- onCreate(SQLiteDatabase db) 第一次建立時回撥
- OnUpgrade(SQLiteDatabase db,int old,int new)版本更新回撥
升級時,只能進行列的插入不能進行列的刪除,因此升級時先進行資料轉儲,清空表重新建立,寫入資料。
使用:
MySQLiteHelper 類
package com.wdl.crazyandroiddemo
import android.content.Context
import android.database.sqlite.SQLiteDatabase
import android.database.sqlite.SQLiteOpenHelper
/**
* author: wdl
* time: 2018/11/13 16:18
* des: SQLite helper類
*/
class MySQLiteHelper constructor(context: Context?, name: String?, factory: SQLiteDatabase.CursorFactory?, version: Int):
SQLiteOpenHelper(context, name, factory, version) {
private val CREATE_STUDENT = "create table student(id integer primary key autoincrement,name text,age integer)"
private val CREATE_BOOK = "create table book(id integer primary key autoincrement,name text,price integer)"
//第一次建立才會執行onCreate,無法完成升級
override fun onCreate(db: SQLiteDatabase?) {
db?.execSQL(CREATE_STUDENT)
db?.execSQL(CREATE_BOOK)
}
override fun onUpgrade(db: SQLiteDatabase?, oldVersion: Int, newVersion: Int) {
when(oldVersion){
1 -> db?.execSQL(CREATE_BOOK)
2 -> db?.execSQL("alter table book add column publishdate integer")
}
}
}
demo:
package com.wdl.crazyandroiddemo
import android.annotation.SuppressLint
import android.content.ContentValues
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_sqlite.*
class SQLiteActivity : AppCompatActivity() {
@SuppressLint("Recycle")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sqlite)
val helper = MySQLiteHelper(this, "demo.db", null, 3)
val db = helper.writableDatabase
mSave.setOnClickListener {
val name = mName.text.toString()
val age = mAge.text.toString().toInt()
val contentValue = ContentValues()
contentValue.put("name", name)
contentValue.put("age", age)
//插入
val index = db.insert("student", null, contentValue).toInt()
if (index == -1) Toast.makeText(this, "插入失敗", Toast.LENGTH_SHORT).show()
}
mQuery.setOnClickListener {
//查詢
val cursor = db.query("student", null, "name like ?", arrayOf("lijie"), null, null, null)
while (cursor.moveToNext()) {
val name = cursor.getString(cursor.getColumnIndexOrThrow("name"))
val age = cursor.getInt(cursor.getColumnIndexOrThrow("age"))
Log.e("wdl", "name = $name,age = $age")
}
cursor.close()
}
mUpdate.setOnClickListener {
val contentValue = ContentValues()
val age = mAge1.text.toString().toInt()
contentValue.put("age", age)
//更新
val index = db.update("student", contentValue, "name = ?", arrayOf("lijie"))
if (index != -1) Toast.makeText(this, "更新成功", Toast.LENGTH_SHORT).show()
}
mDel.setOnClickListener {
val index = db.delete("student","name = ?", arrayOf("wudelin"))
if (index != -1) Toast.makeText(this, "刪除成功", Toast.LENGTH_SHORT).show()
}
}
}
val cursor = db.query(“student”, null, “name like ?”, arrayOf(“lijie”), null, null, null)
while (cursor.moveToNext()) {
val name = cursor.getString(cursor.getColumnIndexOrThrow(“name”))
val age = cursor.getInt(cursor.getColumnIndexOrThrow(“age”))
Log.e(“wdl”, “name = $name,age = $age”)
}
cursor.close()
5.ContentProvider
**
見(https://blog.csdn.net/qq_34341338/article/details/84191392)
**