1. 程式人生 > >第一行程式碼——第六章:資料儲存全方案——詳解持久化技術

第一行程式碼——第六章:資料儲存全方案——詳解持久化技術

目錄:

6.1 持久化技術簡介

6.2 檔案儲存

6.2.1 將資料儲存到檔案中

6.2.2 從檔案中讀出資料

6.3 SharedPreferences 儲存

6.3.1 將資料儲存到SharedPreferences中

6.3.2 從SharedPreferences 中讀取資料

6.3.3 實現記住密碼功能

6.4 SQLite資料庫儲存

6.4.1 建立資料庫

6.4.2 升級資料庫

6.4.3 新增資料

6.4.4 更新資料

6.4.5 刪除資料

6.4.6 查詢資料

6.4.7 使用SQL操作資料庫

6.5 使用LitePal操作資料庫

6.5.1 LitePal簡介

6.5.2 配置LitePal

6.5.3 建立和升級資料庫

6.5.4 使用LitePal新增資料

6.5.5 使用LitePal更新資料

6.5.6 使用LitePal刪除資料

6.5.7 使用LitePal查詢資料

6.6 小結與點評


知識點:

6.1 持久化技術簡介

資料持久化是指將那些記憶體中的瞬時資料儲存到儲存裝置中,保證即使在手機或電腦關機的情況下,這些資料仍然不會丟失。儲存在記憶體中的資料是處於瞬時狀態的,而儲存在儲存裝置中的資料是處於持久狀態的,持久化技術則是提供了一種機制可以讓資料在瞬時狀態和持久狀態之間進行轉換。

Android 系統主要提供了三種方式實現資料持久化功能 即檔案儲存、SharedPreference 儲存以及資料庫儲存。當然,也可以將資料儲存在手機的 SD 卡中,但相對會複雜一些,而且不安全。

6.2 檔案儲存

檔案儲存是 Android 中最基本的一種資料儲存方式,它不對儲存的內容進行任何的格式化處理,所有資料都是原封不動地儲存到檔案當中的,因而它比較適合用於儲存一些簡單的文字資料或二進位制資料。

6.2.1 將資料儲存到檔案中

在這裡,我們通過Context 類中提供了一個 openFileOutput () 方法,用於將資料儲存到指定的檔案中。

Context 類中還提供了一個 openFileInput() 方法,用於從檔案中讀取資料。

 private void save(String string) {
        String data = "Data to save";

        FileOutputStream fos = null;
        BufferedWriter writer = null;
        try {
            fos = openFileOutput("data", Context.MODE_PRIVATE);
            writer = new BufferedWriter(new OutputStreamWriter(fos));
            writer.write(string);

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (writer != null) {
                    writer.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

6.2.2 從檔案中讀出資料

  private void load() {
        FileInputStream in = null;
        BufferedReader reader = null;
        StringBuilder content = new StringBuilder();
        try {
            in = openFileInput("data");
            reader = new BufferedReader(new InputStreamReader(in));
            String line = "";
            while ((line = reader.readLine()) != null) {
                content.append(line);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }
    }

6.3 SharedPreferences 儲存

不同於檔案的儲存方式,SharedPreferences 是使用鍵值對的方式來儲存資料的。

獲取SharedPreferences 物件

  • Context 類中的 getSharedPreferences()方法
      此方法接收兩個引數,第一個引數指定 SharedPreferences 檔案的名稱,第二個引數指定操作模式,目前只有 MODE_PRIVATE 一種模式,和直接傳入 0 效果相同。其他幾種模式已被廢棄。

  • Activity 類中的 getPreferences()方法
      此方法和上面的方法相似,但只接收一個操作模式引數,使用這個方法時會自動將當前活動的類名作為 SharedPreferences 的檔名。

  • PreferenceManager 類中的 getDefaultSharedPreferences()方法
      這是一個靜態方法,它接收一個 Context 引數,並自動使用當前應用程式的包名作為字首來命名 SharedPreferences 檔案。

向sSharedPreferences 中儲存內容

呼叫 SharedPreferences 物件的 edit()方法來獲取一個 SharedPreferences.Editor 物件。
向 SharedPreferences.Editor 物件中新增資料,如新增一個布林型資料使用 putBoolean 方法,新增一個字串使用 putString()方法,以此類推。
呼叫 apply()方法將新增的資料提交,完成資料儲存。

6.3.1 將資料儲存到SharedPreferences中

    SharedPreferences.Editor sp = getSharedPreferences("data", MODE_PRIVATE).edit();
        sp.putString("uid", "1");
        sp.apply();

6.3.2 從SharedPreferences 中讀取資料

//        SharedPreferences sp=getSharedPreferences("data", MODE_PRIVATE);
//        sp.getString()

6.3.3 實現記住密碼功能

我們首先封裝一下SharedPreferences

public class PrefUtils {

    private static final String PREF_NAME = "config";

    /**
     * 讀取布林資料
     * @param ctx 上下文
     * @param key 鍵
     * @param defaultValue 預設值
     * @return
     */
    public static boolean getBoolean(Context ctx, String key,
                                     boolean defaultValue) {
        SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME,
                Context.MODE_PRIVATE);
        return sp.getBoolean(key, defaultValue);
    }

    /**
     * 添加布爾資料
     * @param ctx 上下文
     * @param key 鍵
     * @param value 新增的資料
     */
    public static void setBoolean(Context ctx, String key, boolean value) {
        SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME,
                Context.MODE_PRIVATE);
        sp.edit().putBoolean(key, value).apply();
    }

    /**
     * 讀取字串
     * @param ctx
     * @param key
     * @param defaultValue
     * @return
     */
    public static String getString(Context ctx, String key, String defaultValue) {
        SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME,
                Context.MODE_PRIVATE);
        return sp.getString(key, defaultValue);
    }

    /**
     * 新增字串
     * @param ctx
     * @param key
     * @param value
     */
    public static void setString(Context ctx, String key, String value) {
        SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME,
                Context.MODE_PRIVATE);
        sp.edit().putString(key, value).apply();
    }

    /**
     * 讀取int型別資料
     * @param ctx
     * @param key
     * @param defaultValue
     * @return
     */
    public static int getInt(Context ctx, String key, int defaultValue) {
        SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME,
                Context.MODE_PRIVATE);
        return sp.getInt(key, defaultValue);
    }

    /**
     * 新增int型別資料
     * @param ctx
     * @param key
     * @param value
     */
    public static void setInt(Context ctx, String key, int value){
        SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME,
                Context.MODE_PRIVATE);
        sp.edit().putInt(key, value).apply();
    }

    /**
     * 將資料全部清除掉
     * @param ctx
     */
    public static void clear(Context ctx){
        SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME,
                Context.MODE_PRIVATE);
        sp.edit().clear().apply();
    }
}

然後來編輯下登入介面,修改 activity_login.xml 中的程式碼如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <!--***************** 賬號 *********************-->
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="60dp">
        <TextView
            android:layout_width="90dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:gravity="center"
            android:textSize="18sp"
            android:text="賬號:"/>

        <EditText
            android:id="@+id/et_account"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_gravity="center_vertical"/>
    </LinearLayout>

    <!--***************** 密碼 *********************-->
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="60dp">
        <TextView
            android:layout_width="90dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center_vertical"
            android:gravity="center"
            android:textSize="18sp"
            android:text="密碼:"/>

        <EditText
            android:id="@+id/et_password"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:layout_gravity="center_vertical"
            android:inputType="textPassword"/>
    </LinearLayout>

    <!--***************** 是否記住密碼 *********************-->
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <CheckBox
            android:id="@+id/cb_remember_pass"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="10dp"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="18sp"
            android:layout_gravity="center_vertical"
            android:text="記住密碼"/>

    </LinearLayout>

    <Button
        android:id="@+id/btn_login"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:layout_margin="10dp"
        android:text="登入"/>

</LinearLayout>

只是添加了個 CheckBox 來勾選記住密碼,接著修改 LoginActivity 的程式碼,如下:

public class LoginActivity extends BaseActivity {

    private EditText et_account, et_password;
    private CheckBox cb_remember_pass;
    private Button btn_login;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        et_account = (EditText) findViewById(R.id.et_account);
        et_password = (EditText) findViewById(R.id.et_password);
        cb_remember_pass = (CheckBox) findViewById(R.id.cb_remember_pass);
        btn_login = (Button) findViewById(R.id.btn_login);
        
        Boolean isRemember = PrefUtils.getBoolean(this,"remember_pass",false);
        if (isRemember){
            // 將賬號和密碼都設定到文字框中
            String account = PrefUtils.getString(this,"account","");
            String password = PrefUtils.getString(this,"password","");
            et_account.setText(account);
            et_password.setText(password);
            cb_remember_pass.setChecked(true);
        }

        btn_login.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String account = et_account.getText().toString();
                String password = et_password.getText().toString();
                // 若賬號是 wonderful 且密碼是 123456,就認為登入成功
                if (account.equals("wonderful") && password.equals("123456")){
                    // 檢查複選框是否被勾選
                    if (cb_remember_pass.isChecked()){
                        // 儲存資料到SharePreference檔案中
                        PrefUtils.setBoolean(LoginActivity.this,"remember_pass",true);
                        PrefUtils.setString(LoginActivity.this,"account",account);
                        PrefUtils.setString(LoginActivity.this,"password",password);
                    }else {
                        // 清除SharePreference檔案中的資料
                        PrefUtils.clear(LoginActivity.this);
                    }
                    // 登入成功跳轉到主介面
                    IntentUtils.myIntent(LoginActivity.this,ForceOfflineActivity.class);
                    finish();
                }else {
                    ToastUtils.showShort("賬號或密碼無效!");
                }
            }
        });

    }

    @Override
    protected int initLayoutId() {
        return R.layout.activity_login;
    }
}

具體程式碼就不解釋了,看註釋。

現在執行下程式,輸入賬號和密碼並選中記住密碼複選框後,點選登入,就會跳轉到 ForceOfflineActivity。接著在 ForceOfflineActivity 中發出一條強制下線廣播會讓程式重新回到登入介面, 此時你會發現,賬號密碼都已經自動填充到介面上了,如下:

記住密碼功能效果這樣我們就使用 SharedPreferences 技術將記住密碼功能成功實現了。當然這只是個簡單的示例,實際專案中將密碼以明文的形式儲存在 SharedPreferences 檔案中是不安全的,還需配合加密演算法進行保護。

6.4 SQLite資料庫儲存

6.4.1 建立資料庫

6.4.2 升級資料庫

6.4.3 新增資料

6.4.4 更新資料

6.4.5 刪除資料

6.4.6 查詢資料

6.4.7 使用SQL操作資料庫

以上關於SQLite內容 我單獨寫了一篇文章 請看:

https://blog.csdn.net/lhk147852369/article/details/83307384

6.5 使用LitePal操作資料庫

6.5.1 LitePal簡介

LitePal 是一款開源的 Android 資料庫框架,它採用了物件關係對映(ORM)的模式,並將我們平時開發最常用到的一些資料庫功能進行了封裝,使得不用編寫一行 SQL 語句就可以完成各種建表和增刪查改的操作。LitePal 的專案主頁上也有詳細的使用文件,地址是:https://github.com/LitePalFramework/LitePal

6.5.2 配置LitePal

使用 LitePal 的第一步,在 app/build.gradle 檔案中引入 LitePal 的最新版本:

compile 'org.litepal.android:core:1.4.1'

專案中引入 LitePal 成功後,需要配置 litepal.xml 檔案。右擊 app/src/main 目錄→New→Directory,建立一個 assets 目錄,然後在 assets 目錄下再新建一個 litepal.xml 檔案,接著編輯 litepal.xml 檔案中的內容,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<litepal>
    <!-- 指定資料庫名 -->
    <dbname value="MyBookStore"></dbname>

    <!-- 指定資料庫版本號 -->
    <version value="1"></version>

    <!-- 指定所有的對映模型 -->
    <list>

    </list>
</litepal>

最後還要在 Application 中呼叫 LitePal 的初始化方法:

/**
 * 全域性
 * Created by KXwon on 2016/12/9.
 */
public class MyApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        // 呼叫 LitePal 的初始化方法
        LitePal.initialize(this);
    }
}

當然別忘了在 AndroidManifest.xml 中配置 Application:

<application
    android:name=".MyApplication"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    . . .
 </application>

現在 LitePal 的配置工作完成了,下面正式開始使用它吧。

6.5.3 建立和升級資料庫

郭霖專欄:Android資料庫高手祕籍(二)——建立表和LitePal的基本用法

https://blog.csdn.net/guolin_blog/article/details/38556989

6.5.4 使用LitePal新增資料

郭霖專欄:Android資料庫高手祕籍(五)——LitePal的儲存操作

https://blog.csdn.net/guolin_blog/article/details/39345833

6.5.5 使用LitePal更新資料

6.5.6 使用LitePal刪除資料

郭霖專欄:Android資料庫高手祕籍(六)——LitePal的修改和刪除操作

https://blog.csdn.net/guolin_blog/article/details/40083685

6.5.7 使用LitePal查詢資料

郭霖專欄:

https://blog.csdn.net/guolin_blog/article/details/40153833

6.6 小結與點評

郭霖總結:

經過了這一章漫長的學習,我們終於可以緩解一下疲勞,對本章所學的知識進行核現和總結了。本章主要是對Android常用的資料持久化方式進行了詳細的講解,包括檔案儲存器 SharedPreferences儲存以及資料庫儲存。 其中檔案適用於儲存一-些簡單的文字資料或者二進位制數適用於儲存些鍵值隊 ,而資料庫則適用於儲存那些複雜的關係型資料。雖然目前你已經掌握了這3種資料持久化方式的用法,但是能夠根據專案的實際需求來選擇最合適的方式也是你未來需要繼續探索的。

那麼正如上一章小結裡提到的,既然現在我們已經掌握了Anid中的資料持久化技術,接下來就應該繼續學習 Adoid中剩餘的四大元件了。放鬆下自己,然後一起踏上內容提供器的學習之旅吧。

我的總結:

儲存這一方面也是比較重要的,經過了這章內容的學習,我的能力又有了很大的進步,對於java中的Sterm流 相關的內容 也有了更多的瞭解。