Android 數(shù)據(jù)持久化

Android 數(shù)據(jù)持久化

在 Android 中數(shù)據(jù)持久化的方式有以下幾種。

  1. SQLite
    1. SQLiteOpenHelper
  2. ContentProvider
  3. File
    1. InternalStorage
    2. ExternalStorage
  4. SharedPreferences

SQLite

SQLiteOpenHelper 的使用

官方文檔
SQLiteOpenHelper 詳細(xì)解析
使用 SQLiteOpenHelper 的正確姿勢(shì)
查看當(dāng)前數(shù)據(jù)庫(kù)的工具

關(guān)于 SQLiteOpenHelper 介紹的 blog 已經(jīng)太多了,在這里我盡量多去編程學(xué)習(xí),而不是再?gòu)?fù)述一遍別人說過的話。

總的來說,SQLiteOpenHelper 就是一個(gè)Android 原生的 SQLite 數(shù)據(jù)庫(kù)操作類,里面包含了 數(shù)據(jù)庫(kù)創(chuàng)建,數(shù)據(jù)庫(kù)升級(jí)。并且可以通過 getReadableDatabase(只讀) 和 getWritableDatabase(讀寫) 方法獲取數(shù)據(jù)庫(kù)對(duì)象進(jìn)行CURD。

如今我們用的更多的是 GreenDao, LitePal 等第三方框架來進(jìn)行數(shù)據(jù)庫(kù)操作。這些三方庫(kù)本質(zhì)上就是對(duì) SQLiteOpenHelper 的封裝。

ContentProvider -- 最熟悉的陌生人

ContentProvider 作為 Android 四大組件之一,但對(duì)我來說算是最陌生的一個(gè)。原因是 ContentProvider 用于進(jìn)程間的通訊,而同樣的功能在公司的項(xiàng)目中往往是用 socket 和 udp 實(shí)現(xiàn)的。接下來就記錄一些相關(guān)的知識(shí)

ContentProvider 的介紹

官方文檔

ContentProvider 是一種內(nèi)容共享型的組件。本質(zhì)上是一塊數(shù)據(jù)(以 database,xml 等方式存儲(chǔ)的數(shù)據(jù)),通過 ContentProvider 這層抽象的容器,提供 CURD 的方法,達(dá)到跨進(jìn)程通訊的目的。

官方提供了以下的方法:

  • onCreate() which is called to initialize the provider
  • query(Uri, String[], Bundle, CancellationSignal) which returns data to the caller
  • insert(Uri, ContentValues) which inserts new data into the content provider
  • update(Uri, ContentValues, String, String[]) which updates existing data in the content provider
  • delete(Uri, String, String[]) which deletes data from the content provider
  • getType(Uri) which returns the MIME type of data in the content provider

在我們自定義的類繼承 ContentProvider 后,實(shí)現(xiàn)這些方法。并在 AndroidManifest 中注冊(cè)該類。即可以被其他應(yīng)用訪問了。

數(shù)據(jù)操作離不開 ContentResolver

ContentResolver 根據(jù)不同 ContentProvider 的 URI,來找到對(duì)應(yīng)的 ContentProvider,并進(jìn)行CURD的操作。
我們拿一個(gè)獲取通訊錄信息作為例子:

public fun getContactList(): List<String> {
        val contacts = ArrayList<String>()
        val projection = arrayOf(ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME)
        val query = ContextUtils.getContext()?.contentResolver?.query(ContactsContract.Contacts.CONTENT_URI, projection, null, null, null)
                ?: return contacts
        while (query.isLast) {
            contacts.add(query.getString(PHONES_NUMBER_INDEX))
            query.moveToNext()
        }
        query.close()
        return contacts
    }

Android 文件系統(tǒng)

內(nèi)部存儲(chǔ)

在安裝一個(gè)應(yīng)用的同時(shí),會(huì)在 data/data 目錄下創(chuàng)建一個(gè)與包名對(duì)應(yīng)的文件夾。默認(rèn)情況下,保存到內(nèi)部存儲(chǔ)的文件是應(yīng)用的私有文件,其他應(yīng)用(和用戶)不能訪問這些文件。 當(dāng)用戶卸載您的應(yīng)用時(shí),這些文件也會(huì)被移除。

方法 路徑
Environment.getDataDirectory() /data
Environment.getDownloadCacheDirectory() /cache
Environment.getRootDirectory() /system
  • getFilesDir() 獲取在其中存儲(chǔ)內(nèi)部文件的文件系統(tǒng)目錄的絕對(duì)路徑。
  • getDir() 在您的內(nèi)部存儲(chǔ)空間內(nèi)創(chuàng)建(或打開現(xiàn)有的)目錄。
  • deleteFile() 刪除保存在內(nèi)部存儲(chǔ)的文件。
  • fileList() 返回您的應(yīng)用當(dāng)前保存的一系列文件。

外部存儲(chǔ)

獲取外部存儲(chǔ)的訪問權(quán)限

要讀取或?qū)懭胪獠看鎯?chǔ)上的文件,您的應(yīng)用必須獲取 READ_EXTERNAL_STORAGE 或 WRITE_EXTERNAL_STORAGE 系統(tǒng)權(quán)限。

<manifest ...>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    ...
</manifest>

判斷是否擁有訪問權(quán)限

/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state)) {
        return true;
    }
    return false;
}

/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
    String state = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(state) ||
        Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
        return true;
    }
    return false;
}

常用路徑.png

獲取路徑方式Environment.getExternalStorageDirectory()
(即路徑/storage/sdcard0)

SharedPreferences

> SharedPreferences的理解與使用

SharedPreferences 也是我們常用的數(shù)據(jù)持久化方法之一,這里就不多贅述了,直接上代碼。


object SpUtils {

    private const val FILE_DEFAULT_NAME = "DefaultPreference"

    @JvmStatic
    public fun getSharedPreferences(): SharedPreferences? {
        return ContextUtils.getContext()?.getSharedPreferences(FILE_DEFAULT_NAME, Context.MODE_PRIVATE)
    }

    @JvmStatic
    public fun getSharedPreferences(fileName: String): SharedPreferences? {
        return ContextUtils.getContext()?.getSharedPreferences(fileName, Context.MODE_PRIVATE)
    }

    @JvmStatic
    public fun put(sharedPreferences: SharedPreferences?, key: String, value: Any) {
        var edit = sharedPreferences?.edit()
        when (value) {
            is Int -> edit?.putInt(key, value)
            is String -> edit?.putString(key, value)
            is Boolean -> edit?.putBoolean(key, value)
            is Float, is Double -> edit?.putFloat(key, value as Float)
            is Long -> edit?.putLong(key, value)
        }
        edit?.apply()
    }

    @JvmStatic
    fun contains(sharedPreferences: SharedPreferences?, key: String): Boolean {
        return sharedPreferences?.contains(key) == true
    }

    @JvmStatic
    @Suppress("UNCHECKED_CAST")
    fun <T> get(sharedPreferences: SharedPreferences?, key: String, defaultValue: T): T {
        if (!contains(sharedPreferences, key)) return defaultValue
        when (defaultValue) {
            is Int -> return sharedPreferences?.getInt(key, defaultValue) as T
            is String -> return sharedPreferences?.getString(key, defaultValue) as T
            is Boolean -> return sharedPreferences?.getBoolean(key, defaultValue) as T
            is Float -> return sharedPreferences?.getFloat(key, defaultValue) as T
            is Long -> return sharedPreferences?.getLong(key, defaultValue) as T
        }
        return defaultValue
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容