app ในระบบ android ส่วนใหญ่แล้วจำเป้นต้องมีการจัดเก็บข้อมูล แม้ว่าจะเป็นเพียง
การจัดเก็บข้อมูลเกี่ยวกับ app state ระหว่าง method onPause() ถูกเรียกใช้งานก็ตาม
ด้วยเหตุนี้การดำเนินการของผู้ใช้ก็จะไม่สูญหาย ส่วนใหญ่ app ที่สำคัญๆ ยังต้องการ
ที่จะจัดเก็บการตั้งค่าของผู้ใช้ และ บาง app ต้องมีการจัดการเกี่ยวกับข้อมูลขนาดใหญ่ใน
ไฟล์หรือฐานข้อมูล ในเนื้อหาตอนนี้จะแนะนำเกี่ยวกับหลักการในการจัดเก็บข้อมูล
ในระบบ android ซึ่งประกอบไปด้วย
- การจัดเก็บแบบ key-value ของข้อมูลที่ไม่ซับซ้อนในไฟล์ shared preferences
- การบันทึกไฟล์ที่ไม่มีกฏเกณฑ์ในระบบไฟล์ของ android
- การใช้ฐานข้อมูลจัดการโดย SQLite
การจัดเก็บแบบ key-value
ถ้าเราอยากจะจัดเก็บข้อมูลที่สัมพันธ์ในรูปแบบ key-value ที่มีจำนวนไม่มาก เราควรจะใช้งาน
SharedPreferences API โดย SharedPreferences object จะชีไปยังไฟล์ที่เก็บเป็นชุดข้อมูล
ของ key กับ value และเตรียม method อย่างง่ายในการอ่านและเขียนค่าไว้ให้
ไฟล์ SharedPreferences แต่ละไฟล์ถูกจัดการด้วย Framework และสามารถที่จะกำหนดเป็น
แบบใช้เฉพาะเจาะจง หรือ แบบใช้ร่วมกันได้
เราจะมาดูวิธีการใช้ SharedPreferences APIs เพื่อทำการเก็บ หรือเรียกใช้ข้อมูลอย่างง่ายได้
เข้าใจการจัดการ SharedPreferences
เราสามารถสร้าง shared preference ไฟล์ใหม่ขึ้นมา หรือเข้าใช้งานไฟล์ที่มีอยู่แล้ว โดยการ
เรียกใช้งานอย่างใดอย่างหนึ่งในสอง method ต่อไปนี้
- getSharedPreferences() ใช้ method นี้ถ้าเราจำเป็นต้องใช้ไฟล์ shared preference
หลายอันโดยระบุจากชื่อที่เรากำหนดใน parameter ตัวแรก เราสามารถเรียกใช้งานจาก
ส่วนใดของ app ก็ได้
- getPreferences() ใช้ method นี้จาก activity ถ้าเราจำเป็นต้องใช้เพียง shared
preference แค่ไฟล์เดียวใน activity เพราะ method นี้จะรับค่าจาก shared preference ไฟล์
เริ่มต้นที่เป็นของ activity อยู่แล้ว เราจึงไม่จำเป็นต้องกำหนดชื่อเหมือนกรณี method แรก
เราจะมาทดสอบเพื่อทำความเข้าใจ เกี่ยวกับการใช้งาน SharedPreferences โดยแนวทางที่จะทำคือ
เราจะสร้างหน้าสำหรับ login มี username password และ ก็ button รูปแบบการทำงาน เมื่อเราอยู่หน้า
login และได้ทำการกรอกข้อมูลลงไป แล้วเราออกจาก หน้า login นั้น ในที่นี้ก็จะเป็นการออกจาก app
ในขณะที่เรากำลังออกจาก app ระหว่างเรียก onStop() method เราจะทำการเรียกใช้งาน SharedPreferences
เพื่อเก็บค่า ข้อมูล username password ที่เราได้ทำการกรอกข้อมูลไว้ หลังจากนั้น เมื่อเรากลับเข้ามา
หรือเปิด app ขึ้นมาอีกครั้ง ใน onCreate() method เราจะทำการ อ่านค่าข้อมูลที่บันทึกไว้ใน SharedPreferences
มาใช้งานแสดงในช่อง username และ password แบบนี้เป็นต้น
* เนื่องจากเนื้อหาต่อๆ ไปเกี่ยวกับการเริ่มศึกษา android จะค่อยมีรายละเอียดเยอะขึ้น รวมทั้งเจาะลึกลงไป
ในหลายๆ ส่วน ดังนั้นจะลดการอธิบายเกี่ยวกับรูปภาพ เพราะว่าคิดว่าส่วนใหญ่น่าจะเข้าใจโครงสร้างของไฟล์
แต่ละส่วนกันพอควรแล้ว แต่อย่างไรก็ตาม หากมีส่วนใหม่ที่ยังไม่ได้กล่าวถึง ก็จะยังแสดงรูปภาพประกอบเช่นเคย
1. สร้าง android project ขึ้นมาใหม่ ในที่นี้จะใช้ app ชื่อ Study004 ขั้นตอนการสร้าง project ใหม่ย้อนดูในบทความ
ก่อนๆ ได้เลย
โดยหลังจากที่เราได้ project เริ่มต้นที่พร้อมแล้ว เราจะทำต่อไป โดยบอกก่อนว่า เนื้อหาตอนนี้ เราจะแก้ไขในไฟล์
project เพียง 3 ไฟล์ คือ MainActivity class, activity_main.xml และ strings.xml
2. เริ่มต้นที่ไฟล์ strings.xml ที่ไฟล์นี้เราจะกำหนด string ไว้อ้างชื่อของ SharedPreferences (ตอนนี้เราจะใช้งาน
getSharedPreferences() ส่วน getPreferences() จะไม่ต่างกัน สามารถดัดแปลงเองเพิ่มเติมได้)
เนื่องจาก รูปแบบการเรียกใช้งาน getSharedPreferences() เราต้องกำหนด parameter เข้าไปสองตัวคือ name และ mode
รูปแบบที่เราจะใช้
// กำหนด SharedPreferences instance ชื่อ sharedPref // เรียกใช้งาน getSharedPreferences method รูปแบบ getSharedPreferences(name,mode); // name ในที่นี้ก็คือชื่อไฟล์ที่เราจะกำหนด จากตัวอย่างเราจะเรียกจาก strings.xml ชื่อ pref_file_login // ด้วย getString(R.string.pref_file_login) // ส่วน mode เราจะใช้แบบเฉพาะ MODE_PRIVATE คือให้เฉพาะ app ของเราเข้าใช้งานค่านี้ SharedPreferences sharedPref = getSharedPreferences( getString(R.string.pref_file_login),MODE_PRIVATE);
การกำหนดชื่อไฟล์ เขาแนะนำให้ใช้รูปแบบดังนี้ (ชื่อ package.ชื่อที่ต้องการสื่อถึง
เช่น com.example.ninenik.study004.loginData)
ดังนั้นในที่นี้เราจะกำหนด string เพิ่มเข้าไปใน strings.xml ดังนี้
<resources> <string name="app_name">Study004</string> <string name="hello_world">Hello world!</string> <string name="action_settings">Settings</string> <string name="pref_file_login">com.example.ninenik.study004.loginData</string> </resources>
3. ต่อมาเราจะมาจัดการ ที่ไฟล์ activity_main.xml หรือก็คือส่วนหน้าตาที่เราต้องการแสดงเป็นหน้า login
โดยให้จัดรูปแบบประมาณนี้
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <LinearLayout android:layout_marginTop="50dp" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="30sp" android:text="USER LOGIN" android:textAlignment="center" android:layout_weight="1"/> </LinearLayout> <LinearLayout android:layout_marginTop="100dp" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Username" /> <EditText android:id="@+id/txt_username" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" /> </LinearLayout> <LinearLayout android:layout_marginTop="150dp" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Password" /> <EditText android:id="@+id/txt_password" android:layout_width="wrap_content" android:layout_height="wrap_content" android:inputType="textPassword" android:ems="10" android:layout_weight="1" /> </LinearLayout> <LinearLayout android:layout_marginTop="200dp" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <Button android:id="@+id/btn_login" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Log In"/> </LinearLayout> </RelativeLayout>
4. ส่วนสุดท้ายเราจะมาจัดการที่ไฟล์ MainActivity class มาดูในส่วนของ java code
เรามาดู code ไล่ลงไปแต่ละส่วน
package com.example.ninenik.study004; import android.content.SharedPreferences; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.widget.EditText; public class MainActivity extends ActionBarActivity { // กำหนด instance ให้กับ username และ password private EditText txt_username; private EditText txt_password; // กำหนด instance ให้กับชื่อ key ที่จะใช้ใน SharedPreferences private final String KEY_PREF_USERNAME = "username_key"; private final String KEY_PREF_PASSWORD = "password_key"; ,,,,,,,,............. ,,,,,.......
สังเกตว่าเนื่องจากเรามีการใช้งาน SharedPreferences จึงมีการ import class
import android.content.SharedPreferences;
ต่อไปเรามาดูส่วนที่กำหนดเมื่อ onStop() มีการเรียกใช้งาน ในส่วนนี้เราจะได้รู้จีกวิธีการ
จัดเก็บค่า SharedPreferences
@Override protected void onStop() { super.onStop(); // กำหนดค่าให้กับ instance เชื่อมกับ view ที่ต้องการใชงาน txt_username = (EditText) findViewById(R.id.txt_username); txt_password = (EditText) findViewById(R.id.txt_password); // กำหนด string instance เก็บค่าข้อมลที่กรอก String str_username = txt_username.getText().toString().trim().toLowerCase(); String str_password = txt_password.getText().toString(); // กำหนด SharedPreferences instance ชื่อ sharedPref // เรียกใช้งาน getSharedPreferences method รูปแบบ getSharedPreferences(name,mode); // name ในที่นี้ก็คือชื่อไฟล์ที่เราจะกำหนด จากตัวอย่างเราจะเรียกจาก strings.xml ชื่อ pref_file_login // ด้วย getString(R.string.pref_file_login) // ส่วน mode เราจะใช้แบบเฉพาะ MODE_PRIVATE คือให้เฉพาะ app ของเราเข้าใช้งานค่านี้ SharedPreferences sharedPref = getSharedPreferences( getString(R.string.pref_file_login),MODE_PRIVATE); // ส่วนของการบันทึกค่า SharedPreferences SharedPreferences.Editor editor = sharedPref.edit(); editor.putString(KEY_PREF_USERNAME, str_username); editor.putString(KEY_PREF_PASSWORD, str_password); editor.commit(); }
ในขึ้นตอนการบันทึกค่า SharedPreferences เราจะมีการสร้าง SharedPreferences.Editor โดยเรียกใช้ edit()
method
// ส่วนนี้เป็นขึ้นตอนการเขียนค่าแบบ string // กำหนด instance KEY_PREF_USERNAME = ค่าของ instance str_username // กำหนด instance KEY_PREF_PASSWORD = ค่าของ instance str_password editor.putString(KEY_PREF_USERNAME, str_username); editor.putString(KEY_PREF_PASSWORD, str_password);
และปิดท้ายด้วยคำสั่ง editor.commit(); เพื่อให้ทำงานตามที่เรากำหนด ถึงตรงนี้ ก็เท่ากับว่าเมื่อเราปิด app แล้ว
onStop() method ถูกเรียกใช้งาน ระบบก็จะบันทึก SharedPreferences ให้เรียบร้อยแล้ว
ต่อไปมาดูส่วนของการเรียกใช้งานหรือการอ่าน SharedPreferences โดยเมื่อเราเปิด app ขึ้นมาใหม่ และ onCreate()
ถูกเรียกใช้งาน เราจะทำการอ่านค่าจากไฟล์ SharedPreferences มาใช้และแสดงในช่อง username และ password
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // เรียกใช้งาน SharedPreferences SharedPreferences sharedPref = getSharedPreferences( getString(R.string.pref_file_login),MODE_PRIVATE); // กำหนดค่าให้กับ instance เชื่อมกับ view ที่ต้องการใชงาน txt_username = (EditText) findViewById(R.id.txt_username); txt_password = (EditText) findViewById(R.id.txt_password); // กำหนดค่าให้กับ username และ password โดยใช้ค่าจาก SharedPreferences txt_username.setText(sharedPref.getString(KEY_PREF_USERNAME, "")); txt_password.setText(sharedPref.getString(KEY_PREF_PASSWORD, "")); }
ส่วนนี้จะเป็นส่วนของการอ่านค่า SharedPreferences จากไฟล์มาใช้งาน โดยเนื่องจากข้อมูลของเราเป็นแบบ string
เราจึงใช้ getString() ตัวอย่าง sharedPref.getString(KEY_PREF_USERNAME, "") ความหมายคือ ให้รับค่าที่เป็นข้อความ
จาก SharedPreferences ที่มีค่า key เท่ากับ instance ที่ชื่อ KEY_PREF_USERNAME โดยถ้าไม่มีค่าหรือหาไม่เจอ
ให้มีค่าเท่ากับ "" (ค่าว่าง)
จากนั้นก็ใช้ setText() กำหนดค่าให้กับ view แต่ละตัวที่ต้องการ เช่น
txt_username.setText(sharedPref.getString(KEY_PREF_USERNAME, "")); หมายถึง กำหนดค่าที่ได้ให้กับ txt_username
เรามาดูไฟล์ MainActivity class แบบเต็ม
package com.example.ninenik.study004; import android.content.SharedPreferences; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.widget.EditText; public class MainActivity extends ActionBarActivity { // กำหนด instance ให้กับ username และ password private EditText txt_username; private EditText txt_password; // กำหนด instance ให้กับชื่อ key ที่จะใช้ใน SharedPreferences private final String KEY_PREF_USERNAME = "username_key"; private final String KEY_PREF_PASSWORD = "password_key"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // เรียกใช้งาน SharedPreferences SharedPreferences sharedPref = getSharedPreferences( getString(R.string.pref_file_login),MODE_PRIVATE); // กำหนดค่าให้กับ instance เชื่อมกับ view ที่ต้องการใชงาน txt_username = (EditText) findViewById(R.id.txt_username); txt_password = (EditText) findViewById(R.id.txt_password); // กำหนดค่าให้กับ username และ password โดยใช้ค่าจาก SharedPreferences txt_username.setText(sharedPref.getString(KEY_PREF_USERNAME, "")); txt_password.setText(sharedPref.getString(KEY_PREF_PASSWORD, "")); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_main, menu); return true; } @Override protected void onStop() { super.onStop(); // กำหนดค่าให้กับ instance เชื่อมกับ view ที่ต้องการใชงาน txt_username = (EditText) findViewById(R.id.txt_username); txt_password = (EditText) findViewById(R.id.txt_password); // กำหนด string instance เก็บค่าข้อมลที่กรอก String str_username = txt_username.getText().toString().trim().toLowerCase(); String str_password = txt_password.getText().toString(); // กำหนด SharedPreferences instance ชื่อ sharedPref // เรียกใช้งาน getSharedPreferences method รูปแบบ getSharedPreferences(name,mode); // name ในที่นี้ก็คือชื่อไฟล์ที่เราจะกำหนด จากตัวอย่างเราจะเรียกจาก strings.xml ชื่อ pref_file_login // ด้วย getString(R.string.pref_file_login) // ส่วน mode เราจะใช้แบบเฉพาะ MODE_PRIVATE คือให้เฉพาะ app ของเราเข้าใช้งานค่านี้ SharedPreferences sharedPref = getSharedPreferences( getString(R.string.pref_file_login),MODE_PRIVATE); // ส่วนของการบันทึกค่า SharedPreferences SharedPreferences.Editor editor = sharedPref.edit(); editor.putString(KEY_PREF_USERNAME, str_username); editor.putString(KEY_PREF_PASSWORD, str_password); editor.commit(); } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
5. ทดสอบ run app ของเรา หากไม่มีปัญหา จะได้ผลลัพธ์ ตามลำดับเหตุการณ์ตามนี้