1. 程式人生 > >Android資料儲存的方式

Android資料儲存的方式

1.Android常用的資料儲存方式

  1. File儲存
  2. SharedPreferences儲存
  3. SQLite輕量型資料庫
  4. ContentProvider 四大元件之一

2.File儲存

最基本的一種資料儲存方式,不對儲存的內容進行任何的格式化處理,所有資料都是原封不動的儲存到檔案中,適合儲存一些簡單的文字資料或二進位制資料。儲存的資料位於/data/data/< package name>/files/目錄下
Context類中提供了2種常用方法:

  1. openFileOutput(“fileName”,mode)開啟檔案輸出流,從程式種寫入到指定檔案
    第一個引數代表檔名稱,不能包含路徑。第一個為檔案的操作模式:

    Context.MODE_PRIVATE 預設操作模式,檔案存在時覆蓋檔案的內容
    Context.MODE_APPEND 檔案已存在,內容追加。不存在則自動建立新檔案
    Context.MODE_WORLD_READABLE 允許其他程式進行讀操作
    Context.MODE_WORLD_WRITEABLE 允許其他程式進行讀寫操作
    

後兩種模式在4.2後已被廢棄

  1. openFileInput(“fileName”)開啟檔案輸入流,從檔案種讀取檔案並讀取到程式
  2. getDir(String name,int mode)在應用程式的資料資料夾下獲取或建立name對應的子目錄
  3. getFilesDir() 資料資料夾的絕對路徑
  4. fileList() 資料資料夾下的全部檔案
  5. 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代表一個數據庫,提供以下靜態方法開啟對應的資料庫:

  1. openDatabase(String path,SQLiteDatabase.CursorFactory factory,int flags) 開啟path檔案所代表的SQLite資料庫
  2. openOrCreateDatabase(File file,CursorFactory factory)開啟或(如果不存在)建立file檔案所代表的SQLite資料庫
  3. 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,提供如下方法:

  1. moveToFirst() 將指標移到第一行,成功返回true
  2. moveToLast() 將指標移到最後一行,成功返回true
  3. moveToNext()將指標移到下一行,成功返回true
  4. moveToPosition(int position)將指標移到指定行
  5. moveToPrevious() 將指標移到上一行,成功返回true

Sqlite3常用指令:

  1. .databases 檢視當前資料庫

  2. .tables 檢視所有表

  3. .help 檢視支援的命令

    特點:內部只支援NULL,INTEGER,REAL,TEXT,BLOB,實際可接受varchar,char,decimal等資料型別,運算或儲存時將它們轉換為以上的型別。允許把各種型別的資料儲存到任何型別欄位中.

事務

  1. beginTransaction() 開始事務
  2. endTransaction() 結束事務
  3. inTransaction() 判斷是否處於事務環境中
    注意:
    當程式執行endTransaction() 方法時會結束事務,那到底是提交事務還是回滾事務,取決於SQLiteDatabase是否呼叫了setTransactionSuccessful()設定事務標誌,如果設定則提交,否則則回滾事務。

SQLiteOpenHleper類

專案中通常繼承SQLiteOpenHleper類開發子類,通過如下方法:

  1. synchronized SQLiteDatabase getReadableDatabase() 以讀寫的方式開啟對應資料庫,磁碟滿 只讀
  2. synchronized SQLiteDatabase getWriteableDatabase()以寫的方式開啟對應資料庫,磁碟滿會出錯
  3. onCreate(SQLiteDatabase db) 第一次建立時回撥
  4. 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)

**