第一行代碼讀書筆記 6 -- 持久化技術(shù)(上)

本篇文章主要介紹以下幾個(gè)知識(shí)點(diǎn):

  • 文件存儲(chǔ)镐侯;
  • SharedPreference 存儲(chǔ);
  • 實(shí)戰(zhàn):實(shí)現(xiàn)記住密碼功能
圖片來源網(wǎng)絡(luò)

數(shù)據(jù)持久化是指將那些內(nèi)存中的瞬時(shí)數(shù)據(jù)保存到存儲(chǔ)設(shè)備中,保證即使在手機(jī)或電腦關(guān)機(jī)的情況下伺糠,這些數(shù)據(jù)仍然不會(huì)丟失檀轨。保存在內(nèi)存中的數(shù)據(jù)是處于瞬時(shí)狀態(tài)的胸竞,而保存在存儲(chǔ)設(shè)備中的數(shù)據(jù)是處于持久狀態(tài)的,持久化技術(shù)則是提供了一種機(jī)制可以讓數(shù)據(jù)在瞬時(shí)狀態(tài)和持久狀態(tài)之間進(jìn)行轉(zhuǎn)換参萄。

Android 系統(tǒng)中主要提供了三種方式實(shí)現(xiàn)數(shù)據(jù)持久化功能卫枝, 即文件存儲(chǔ)、SharedPreference 存儲(chǔ)以及數(shù)據(jù)庫(kù)存儲(chǔ)讹挎。當(dāng)然剃盾,也可以將數(shù)據(jù)保存在手機(jī)的 SD 卡中,但相對(duì)會(huì)復(fù)雜一些淤袜,而且不安全痒谴。

6.1 文件存儲(chǔ)

文件存儲(chǔ)是 Android 中最基本的一種數(shù)據(jù)存儲(chǔ)方式,它不對(duì)存儲(chǔ)的內(nèi)容進(jìn)行任何的格式化處理铡羡,所有數(shù)據(jù)都是原封不動(dòng)地保存到文件當(dāng)中的积蔚,因而它比較適合用于存儲(chǔ)一些簡(jiǎn)單的文本數(shù)據(jù)或二進(jìn)制數(shù)據(jù)。

Context 類中提供了一個(gè) openFileOutput () 方法烦周,用于將數(shù)據(jù)存儲(chǔ)到指定的文件中尽爆。Context 類中還提供了一個(gè) openFileInput() 方法怎顾,用于從文件中讀取數(shù)據(jù)。

下面通過一個(gè)例子學(xué)習(xí)下在 Android 項(xiàng)目中使用文件存儲(chǔ)的技術(shù)漱贱。首先創(chuàng)建一個(gè)項(xiàng)目槐雾,并修改其布局代碼:

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

    <EditText
        android:id="@+id/edit_test"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Type something here"/>

</RelativeLayout>

這里只是在布局中加入了一個(gè) EditText,用于輸入文本內(nèi)容幅狮。我們的目的是在文本輸入框中隨意輸入內(nèi)容募强,然后按下 Back 鍵,將輸入的內(nèi)容保存到文件中崇摄,再重新啟動(dòng)程序擎值,剛才輸入的內(nèi)容不丟失。

修改 activity 中的代碼(具體內(nèi)容見注解)逐抑,如下:

public class FilePersistenceActivity extends AppCompatActivity {

    private EditText editText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_file_persistence);
        
        editText = (EditText) findViewById(R.id.edit_test);
        String inputText = load();
        if (!TextUtils.isEmpty(inputText)){
            editText.setText(inputText);
            editText.setSelection(inputText.length()); // 將輸入光標(biāo)移到文本末尾位置
            ToastUtils.showShort("重啟讀取存儲(chǔ)的內(nèi)容成功");
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        String inputText = editText.getText().toString();
        // 在活動(dòng)銷毀前把輸入的內(nèi)容存儲(chǔ)到文件中
        save(inputText);
    }

    /**
     * 把內(nèi)容存儲(chǔ)到文件
     * @param inputText 存儲(chǔ)的內(nèi)容
     */
    public void save(String inputText) {
        FileOutputStream out = null;
        BufferedWriter writer = null;
        try {
            // openFileOutput方法接收兩個(gè)參數(shù):
            // 第一個(gè)是不包含路徑的文件名 (默認(rèn)存儲(chǔ)到/data/data/<package name>/files/目錄下)
            // 第二個(gè)是文件的操作模式,有兩種可選:
            // 1.MODE_PRIVATE(默認(rèn)):當(dāng)指定同樣文件名的時(shí)候,所寫入的內(nèi)容將會(huì)覆蓋原文件中的內(nèi)容
            // 2.MODE_APPEND:若該文件已存在就往文件里面追加內(nèi)容,不存在就創(chuàng)建新文件鸠儿。
            // (注:其他操作模式過于危險(xiǎn),在 Android 4.2 已被廢棄)
            // openFileOutput方法返回的是一個(gè)FileOutputStream對(duì)象
            out = openFileOutput("data", Context.MODE_PRIVATE);
            // 構(gòu)建OutputStreamWriter對(duì)象后,構(gòu)建BufferedWriter對(duì)象
            writer = new BufferedWriter(new OutputStreamWriter(out));
            // 將文本寫入文件
            writer.write(inputText);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (writer != null){
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 從文件中讀取數(shù)據(jù)
     * @return 讀取的內(nèi)容
     */
    public String load(){
        FileInputStream in = null;
        BufferedReader reader = null;
        StringBuilder content = new StringBuilder();
        try {
            // openFileInput只接收一個(gè)參數(shù),即要讀取的文件名,然后系統(tǒng)會(huì)自動(dòng)到
            // /data/data/<package name>/files/目錄下去加載這個(gè)文件,并返回一個(gè)FileInputStream對(duì)象.
            in = openFileInput("data");
            // 構(gòu)建InputStreamReader對(duì)象后,構(gòu)建BufferedReader對(duì)象
            reader = new BufferedReader(new InputStreamReader(in));
            String line = "";
            // 讀取內(nèi)容
            while ((line = reader.readLine())!= null){
                content.append(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null){
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return content.toString();
    }
}

運(yùn)行程序厕氨,輸入wonderful 后退出程序再重啟进每,剛輸入的內(nèi)容并不會(huì)丟失,還原到了輸入框中命斧,如圖所示:

還原保存成功的內(nèi)容

文件存儲(chǔ)所用到的核心技術(shù)就是 Context 類中提供的 openFileInput() 和 openFileOutput() 方法田晚,之后就是利用 Java 的各種流來進(jìn)行讀寫操作就可以了。

文件存儲(chǔ)的方式并不適合用于保存一些較為復(fù)雜的文本數(shù)據(jù)冯丙,因此肉瓦,下面就來學(xué)習(xí)一下 Android 中另一種數(shù)據(jù)持久化的方式,它比文件存儲(chǔ)更加簡(jiǎn)單易用胃惜,而且可以很方便地對(duì)某一指定的數(shù)據(jù)進(jìn)行讀寫操作泞莉。

6.2 SharedPreferences 存儲(chǔ)

不同于文件的存儲(chǔ)方式,SharedPreferences 是使用鍵值對(duì)的方式來存儲(chǔ)數(shù)據(jù)的船殉。

6.2.1 將數(shù)據(jù)存儲(chǔ)到 SharedPreferences 中

要想使用 SharedPreferences 來存儲(chǔ)數(shù)據(jù)鲫趁,首先需要獲取到 SharedPreferences 對(duì)象。Android 提供了三種方法得到 SharedPreferences 對(duì)象:

  • Context 類中的 getSharedPreferences()方法
    ??此方法接收兩個(gè)參數(shù)利虫,第一個(gè)參數(shù)指定 SharedPreferences 文件的名稱挨厚,第二個(gè)參數(shù)指定操作模式,目前只有 MODE_PRIVATE 一種模式糠惫,和直接傳入 0 效果相同疫剃。其他幾種模式已被廢棄。

  • Activity 類中的 getPreferences()方法
    ??此方法和上面的方法相似硼讽,但只接收一個(gè)操作模式參數(shù)巢价,使用這個(gè)方法時(shí)會(huì)自動(dòng)將當(dāng)前活動(dòng)的類名作為 SharedPreferences 的文件名。

  • PreferenceManager 類中的 getDefaultSharedPreferences()方法
    ??這是一個(gè)靜態(tài)方法,它接收一個(gè) Context 參數(shù)壤躲,并自動(dòng)使用當(dāng)前應(yīng)用程序的包名作為前綴來命名 SharedPreferences 文件城菊。

得到了 SharedPreferences 對(duì)象之后,分為三步實(shí)現(xiàn)向 SharedPreferences 文件中存儲(chǔ)數(shù)據(jù):
??(1)調(diào)用 SharedPreferences 對(duì)象的 edit()方法來獲取一個(gè) SharedPreferences.Editor 對(duì)象碉克。
??(2)向 SharedPreferences.Editor 對(duì)象中添加數(shù)據(jù)凌唬,如添加一個(gè)布爾型數(shù)據(jù)使用 putBoolean 方法,添加一個(gè)字符串使用 putString()方法漏麦,以此類推客税。
??(3) 調(diào)用 apply()方法將添加的數(shù)據(jù)提交,完成數(shù)據(jù)存儲(chǔ)唁奢。

當(dāng)然霎挟,SharedPreference在提交數(shù)據(jù)時(shí)也可用 Editor 的 commit 方法窝剖,兩者區(qū)別如下:

  • apply() 沒有返回值而 commit() 返回 boolean 表明修改是否提交成功
  • apply() 將修改提交到內(nèi)存麻掸,然后再異步提交到磁盤上;而 commit() 是同步提交到磁盤上。** 谷歌建議:若在UI線程中赐纱,使用 apply() 減少UI線程的阻塞(寫到磁盤上是耗時(shí)操作)引起的卡頓脊奋。**

接下來通過個(gè)例子來體驗(yàn)下。新建一個(gè)項(xiàng)目疙描,修改其布局文件代碼诚隙,如下:

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

    <Button
        android:id="@+id/save_data"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="保存數(shù)據(jù)" />

</LinearLayout>

放一個(gè)按鈕,將一些數(shù)據(jù)存儲(chǔ)到SharedPreferences 文件當(dāng)中起胰。然后修改 Activity 中的代碼久又,如下所示:

public class SharePreferencesActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_share_preferences);

        Button save_data = (Button) findViewById(R.id.save_data);
        save_data.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // 1.指定文件名為 wonderful,并得到 SharedPreferences.Editor 對(duì)象
                SharedPreferences.Editor editor = getSharedPreferences("wonderful",MODE_PRIVATE).edit();
                // 2.添加數(shù)據(jù)
                editor.putString("name","開心wonderful");
                editor.putInt("age",20);
                editor.putBoolean("married",false);
                // 3.數(shù)據(jù)提交
                editor.apply();
            }
        });
    }
}

運(yùn)行程序效五,點(diǎn)擊按鈕后地消,這時(shí)數(shù)據(jù)已保存成功了。接下來借助 File Explorer 來進(jìn)行查看:打開 Android Device Monitor→點(diǎn)擊 File Explorer 標(biāo)簽頁→進(jìn)入/data/data/com. wonderful.myfirstcode/shared_prefs /目錄畏妖,可以看到生成了一個(gè) wonderful.xml 文件脉执,如下:

生成的 wonderful.xml 文件

用記事本打開這個(gè)文件,里面內(nèi)容如圖所示:

wonderful.xml 文件中的內(nèi)容

可以看到戒劫,在按鈕的點(diǎn)擊事件中添加的所有數(shù)據(jù)都已經(jīng)成功保存下來了半夷,并且SharedPreferences 文件是使用 XML 格式來對(duì)數(shù)據(jù)進(jìn)行管理的。

6.2.2 從 SharedPreferences 中讀取數(shù)據(jù)

SharedPreferences 對(duì)象中提供了一系列的 get 方法用于對(duì)存儲(chǔ)的數(shù)據(jù)進(jìn)行讀取迅细,每種 get 方法都對(duì)應(yīng)了 SharedPreferences. Editor 中的一種 put 方法巫橄。這些 get 方法接收兩個(gè)參數(shù),第一個(gè)參數(shù)是鍵茵典,即傳入存儲(chǔ)數(shù)據(jù)時(shí)使用的鍵湘换;第二個(gè)參數(shù)是默認(rèn)值,即當(dāng)傳入的鍵找不到對(duì)應(yīng)的值時(shí),返回默認(rèn)值枚尼。

還是例子實(shí)在贴浙,修改上面項(xiàng)目中的布局代碼:

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

    <Button
        android:id="@+id/save_data"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="保存數(shù)據(jù)" />

    <Button
        android:id="@+id/restore_data"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="讀取數(shù)據(jù)" />
    
    <TextView
        android:id="@+id/show_data"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

這里增加了一個(gè)還原數(shù)據(jù)的按鈕和 TextView,點(diǎn)擊按鈕來從 SharedPreferences 文件中讀取數(shù)據(jù)并在 TextView 中顯示讀取的數(shù)據(jù)署恍。修改 Activity 中的代碼崎溃,如下所示:

public class SharePreferencesActivity extends AppCompatActivity {
    
    private Button save_data,restore_data;
    
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_share_preferences);

        save_data = (Button) findViewById(R.id.save_data);
        save_data.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // 1.指定文件名為 wonderful,并得到 SharedPreferences.Editor 對(duì)象
                SharedPreferences.Editor editor = getSharedPreferences("wonderful",MODE_PRIVATE).edit();
                // 2.添加不同類型的數(shù)據(jù)
                editor.putString("name","開心wonderful");
                editor.putInt("age",20);
                editor.putBoolean("married",false);
                // 3.數(shù)據(jù)提交
                editor.apply();
            }
        });

        textView = (TextView) findViewById(R.id.show_data);
        restore_data = (Button) findViewById(R.id.restore_data);
        restore_data.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // 獲得 SharedPreferences 對(duì)象
                SharedPreferences pref = getSharedPreferences("wonderful",MODE_PRIVATE);
                // 獲取相應(yīng)的值
                String name = pref.getString("name","");
                int age = pref.getInt("age",0);
                boolean married = pref.getBoolean("married",false);
                // 將獲取到的值顯示
                textView.setText("name is " + name + ",age is "+ age + ",married is "+ married);
            }
        });
    }
}

重新運(yùn)行一下程序盯质,并點(diǎn)擊界面上的 讀取數(shù)據(jù) 按鈕袁串,然后查看 TextView中顯示的信息,如下:

讀取數(shù)據(jù)并顯示效果

所有之前存儲(chǔ)的數(shù)據(jù)都成功讀取出來了呼巷!相比之下囱修,SharedPreferences 存儲(chǔ)要比文件存儲(chǔ)簡(jiǎn)單方便了許多。

6.2.3 實(shí)現(xiàn)記住密碼功能

接下來王悍,通過一個(gè)實(shí)現(xiàn)記住密碼功能破镰,來加深對(duì) SharedPreferences 的學(xué)習(xí)。這里繼續(xù)用上一章廣播的強(qiáng)制下線的例子压储。

修改項(xiàng)目前鲜漩,先來簡(jiǎn)單封裝下關(guān)于 SharedPreferences 的工具類,如下:

/**
 * SharePreference封裝
 * Created by KXwon on 2016/7/1.
 */
public class PrefUtils {

    private static final String PREF_NAME = "config";

    /**
     * 讀取布爾數(shù)據(jù)
     * @param ctx 上下文
     * @param key 鍵
     * @param defaultValue 默認(rèn)值
     * @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);
    }

    /**
     * 添加布爾數(shù)據(jù)
     * @param ctx 上下文
     * @param key 鍵
     * @param value 添加的數(shù)據(jù)
     */
    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類型數(shù)據(jù)
     * @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類型數(shù)據(jù)
     * @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();
    }

    /**
     * 將數(shù)據(jù)全部清除掉
     * @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">

    <!--***************** 賬號(hào) *********************-->
    <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="賬號(hào):"/>

        <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>

只是添加了個(gè) 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){
            // 將賬號(hào)和密碼都設(shè)置到文本框中
            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();
                // 若賬號(hào)是 wonderful 且密碼是 123456刮刑,就認(rèn)為登錄成功
                if (account.equals("wonderful") && password.equals("123456")){
                    // 檢查復(fù)選框是否被勾選
                    if (cb_remember_pass.isChecked()){
                        // 保存數(shù)據(jù)到SharePreference文件中
                        PrefUtils.setBoolean(LoginActivity.this,"remember_pass",true);
                        PrefUtils.setString(LoginActivity.this,"account",account);
                        PrefUtils.setString(LoginActivity.this,"password",password);
                    }else {
                        // 清除SharePreference文件中的數(shù)據(jù)
                        PrefUtils.clear(LoginActivity.this);
                    }
                    // 登錄成功跳轉(zhuǎn)到主界面
                    IntentUtils.myIntent(LoginActivity.this,ForceOfflineActivity.class);
                    finish();
                }else {
                    ToastUtils.showShort("賬號(hào)或密碼無效喉祭!");
                }
            }
        });

    }

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

具體代碼就不解釋了,看注釋雷绢。

現(xiàn)在運(yùn)行下程序泛烙,輸入賬號(hào)和密碼并選中記住密碼復(fù)選框后,點(diǎn)擊登錄习寸,就會(huì)跳轉(zhuǎn)到 ForceOfflineActivity胶惰。接著在 ForceOfflineActivity 中發(fā)出一條強(qiáng)制下線廣播會(huì)讓程序重新回到登錄界面, 此時(shí)你會(huì)發(fā)現(xiàn)霞溪,賬號(hào)密碼都已經(jīng)自動(dòng)填充到界面上了孵滞,如下:

記住密碼功能效果

這樣我們就使用 SharedPreferences 技術(shù)將記住密碼功能成功實(shí)現(xiàn)了。當(dāng)然這只是個(gè)簡(jiǎn)單的示例鸯匹,實(shí)際項(xiàng)目中將密碼以明文的形式存儲(chǔ)在 SharedPreferences 文件中是不安全的坊饶,還需配合加密算法進(jìn)行保護(hù)。

關(guān)于 SharedPreferences 的學(xué)習(xí)就到這殴蓬,接下來會(huì)在下一篇文章中學(xué)習(xí) Android 中的數(shù)據(jù)庫(kù)技術(shù)匿级。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蟋滴,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子痘绎,更是在濱河造成了極大的恐慌津函,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,430評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件孤页,死亡現(xiàn)場(chǎng)離奇詭異尔苦,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)行施,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門允坚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蛾号,你說我怎么就攤上這事稠项。” “怎么了鲜结?”我有些...
    開封第一講書人閱讀 167,834評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵展运,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我轻腺,道長(zhǎng)乐疆,這世上最難降的妖魔是什么划乖? 我笑而不...
    開封第一講書人閱讀 59,543評(píng)論 1 296
  • 正文 為了忘掉前任贬养,我火速辦了婚禮,結(jié)果婚禮上琴庵,老公的妹妹穿的比我還像新娘误算。我一直安慰自己,他們只是感情好迷殿,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評(píng)論 6 397
  • 文/花漫 我一把揭開白布儿礼。 她就那樣靜靜地躺著,像睡著了一般庆寺。 火紅的嫁衣襯著肌膚如雪蚊夫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,196評(píng)論 1 308
  • 那天懦尝,我揣著相機(jī)與錄音知纷,去河邊找鬼。 笑死陵霉,一個(gè)胖子當(dāng)著我的面吹牛琅轧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播踊挠,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼乍桂,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起睹酌,我...
    開封第一講書人閱讀 39,671評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤权谁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后憋沿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體闯传,經(jīng)...
    沈念sama閱讀 46,221評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評(píng)論 3 340
  • 正文 我和宋清朗相戀三年卤妒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了甥绿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,444評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡则披,死狀恐怖共缕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情士复,我是刑警寧澤图谷,帶...
    沈念sama閱讀 36,134評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站阱洪,受9級(jí)特大地震影響便贵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜冗荸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評(píng)論 3 333
  • 文/蒙蒙 一承璃、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蚌本,春花似錦盔粹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至嵌莉,卻和暖如春进萄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背锐峭。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工中鼠, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人只祠。 一個(gè)月前我還...
    沈念sama閱讀 48,837評(píng)論 3 376
  • 正文 我出身青樓兜蠕,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親抛寝。 傳聞我的和親對(duì)象是個(gè)殘疾皇子熊杨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容