สำหรับบทความนี้จริงๆแล้วเจ้าของบล็อกก็ควรที่จะทำไว้ตั้งนานแล้วล่ะ แต่ก็ดองไว้ข้ามเดือนข้ามปีจนกระทั่งจะสำนึกได้ว่าควรจะทำบทความนี้ซะที
บ่อยครั้งที่มีผู้ที่หลงเข้ามาอ่านอยากจะเขียนให้แอปพลิเคชันจำข้อมูลบางอย่างไว้เมื่อผู้ใช้ปิดแอปพลิเคชัน และเมื่อเปิดขึ้นมาใหม่ก็จะมีข้อมูลนั้นๆอยู่เหมือนเดิมไม่จางหายไปจากเธอ~♪ (มั่วละ) ซึ่งผู้ที่หลงเข้ามาอ่านส่วนใหญ่ก็จะนึกถึงฐานข้อมูล (Database) หรือไม่ก็เก็บลงใน External Storage หรือถ้ามองไปการไกลกว่านั้นก็จะเป็นการเก็บขึ้น Web Server
แต่บทความนี้จะมาแนะนำให้รู้จักกับคลาสตัวหนึ่งที่เกิดมาเพื่อการนี้โดยเฉพาะ (Born to be เลยก็ว่าได้) ซึ่งมีชื่อว่า Shared Preferences ที่ผู้ที่หลงเข้ามาอ่านหลายๆคนอาจจะยังไม่เคยรู้จัก (เนื่องจากมีผู้ที่หลงเข้ามาอ่านหลายๆคนบอกว่าพึ่งจะรู้ว่ามีคลาสแบบนี้ด้วย)
ปกติการเก็บข้อมูลลงในเครื่อง (ปิดแอปพลิเคชันแล้วเปิดขึ้นมาใหม่ก็ยังคงไม่หาย) ถ้าเป็นข้อมูลจำนวนมากๆก็มักจะใช้ฐานข้อมูล และถ้าเป็นไฟล์ต่างๆก็มักจะเก็บลงใน External Storage (ซึ่งต่อไปขอเรียกว่า "เก็บข้อมูลถาวร")
เกร็ดความรู้เพิ่มเติม : การเก็บข้อมูลแบบถาวรเรียกว่า "Persistent Storage"
แต่ถ้าอยากเก็บแค่ค่าของตัวแปรซักสองสามตัวล่ะ?
ซึ่งการสร้างฐานข้อมูลขึ้นมาเพื่อเก็บข้อมูลแค่นั้นก็คงสิ้นเปลืองซะเปล่า และสร้างเป็น Text File เก็บเป็นข้อความเป็นไฟล์ .txt ลงในเครื่องก็ยิ่งยุ่งยากเข้าไปใหญ่ ดังนั้นจึงถือกำเนิด Shared Preferences ขึ้นมาเพื่อการนี้นั่นเอง
Shared Preferences เป็นคลาสที่ใช้สำหรับเก็บข้อมูลถาวรที่เป็นค่าของตัวแปรธรรมดาๆ อย่างเช่น Boolean Integer หรือ Float เป็นต้น ดังนั้นอยากจะเก็บค่าของตัวแปรก็แนะนำให้ใช้คลาสตัวนี้แทน
โดย Shared Preferences จะมีอยู่ด้วยกันสองแบบคือ Shared Preferences กับ Preferences
Shared Preference จะเป็นการเก็บข้อมูลตัวแปรที่สามารถดึงไปใช้งานที่ไหนก็ได้ภายในแอปพลิเคชันนั้นๆ ดังนั้นถ้าจะส่งข้อมูลระหว่าง Activity ก็ใช้ Shared Preferences ได้เหมือนกันนะ เช่น Activity A เก็บข้อมูลบางอย่าง แล้วให้ Activity B ดึงขึ้นมาใช้งาน เป็นต้น แต่ทว่าส่งผ่าน Extras ของ Intent นั้นง่ายกว่า
Preferences จะเป็นการเก็บข้อมูลตัวแปรที่ใช้งานได้เฉพาะที่ที่เรียกใช้เท่านั้น เช่น Activity A สร้าง Preferences เก็บค่าบางอย่างไว้ เมื่อ Activity B จะดึงค่าที่ Activity A เก็บไว้ก็จะไม่สามารถทำได้
ซึ่งทั้งสองมีความต่างกันแค่คำสั่งที่เรียกใช้ แต่อย่างอื่นนั้นเหมือนกัน
สำหรับ Shared Preferences
SharedPreferences sp = getSharedPreferences(name, mode);
สำหรับ Preferences
SharedPreferences sp = getPreferences(mode);
โดยทั้งสองจะต่างกันแค่ชื่อของ Shared Preferences เท่านั้น เพราะว่า Preferences จะอิงจาก Activity ที่เรียกใช้ ดังนั้นไม่จำเป็นต้องระบุชื่อ แต่สำหรับ Shared Preferences ที่สามารถถูกเรียกใช้ตอนไหนก็ได้ จึงต้องมีการกำหนดชื่อไฟล์เองเพื่อให้ผู้ที่หลงเข้ามาอ่านจัดการได้อย่างยืดหยุ่น (ซึ่งจะพูดในทีหลัง) และในตัวอย่างนี้เจ้าของบล็อกขอหยิบยก Shared Preferences มาอธิบายนะ
สำหรับข้อมูลตัวแปรที่จะเก็บด้วย Shared Preferences จะมีทั้งหมดดังนี้
• Boolean
• Float
• Integer
• Long
• Long
• String
• String Set (Array)
ถ้านอกเหนือจากนี้ก็เสียใจด้วยนะ เพราะว่ามันเกิดมาเพื่อเก็บข้อมูลจากตัวแปรเท่านั้น
การเรียกใช้งานจะมีหลักการอยู่ง่ายๆคือ อยากจะใช้ก็เรียก Shared Preferences ก่อนแล้วค่อยดึงข้อมูล และถ้าอยากจะเก็บข้อมูลก็เรียก Shared Preferences Editor แล้วค่อยเก็บข้อมูลลงไป
• คลาส SharedPreferences : ดึงข้อมูลจาก Shared Preferences
• คลาส SharedPreferences.Editor : เก็บข้อมูลลงใน Shared Preferences
การเก็บข้อมูลลงใน Shared Preferences
ในการใช้งานเพื่อเก็บข้อมูลลงใน Shared Preferences ก็จะต้องเรียกจากคลาส SharedPreferences.Editor ดังนี้
ยกตัวอย่างเช่น
โดยที่ PREF_NAME เป็นชื่อ Shared Preferences ที่ต้องการ ซึ่งเป็นชื่ออะไรก็ได้ เพราะมันจะไปกลายเป็นชื่อไฟล์ที่เก็บลงในเครื่อง เพราะงั้นถ้าจะดึงข้อมูลมาใช้งานก็เรียกชื่อไฟล์ให้ถูกด้วยล่ะ ส่วน Context.MODE_PRIVATE เป็นการกำหนดรูปแบบของการสร้างไฟล์ ซึ่งในที่นี้คือการสร้างไฟล์โดยให้ไฟล์นั้นสามารถเข้าถึงได้จากแอปพลิเคชันนี้เท่านั้น (หรือแอปพลิเคชันที่มี UID เหมือนกัน)
เพราะงั้นหัวใจหลักจะอยู่แค่ว่าจะกำหนดไฟล์ Shared Preferences เป็นชื่ออะไร จากนั้นเวลาจะเก็บข้อมูลก็ทำผ่าน editor สมมติว่าเจ้าของบล็อกอยากจะเก็บข้อมูลจากตัวแปร Integer ซักตัวก็จะได้แบบนี้
จะเห็นว่าการเก็บค่า Integer ลงใน Shared Preferences จะต้องมีการกำหนด Keyword ด้วย คล้ายๆกับการส่งข้อมูลระหว่าง Activity นั่นเอง โดยในตัวอย่างก็กำหนดให้เก็บข้อมูลลงไปโดยใช้ชื่อว่า My_Value ส่วนค่าที่เก็บก็คือค่าจากตัวแปร x ที่มีค่าเป็น 100 นั่นเอง ดังนั้น My_Value ก็จะเก็บ 100 ไว้ในนี้
และเมื่อกำหนดข้อมูลที่จะเก็บเสร็จแล้วก็ให้ใช้คำสั่ง Commit เพื่อทำการบันทึกข้อมูลลงใน Shared Preferences เพราะงั้นถ้าใช้คำสั่ง Put เยอะๆแล้วดันไม่ได้ใช้คำสั่ง Commit ต่อท้าย ข้อมูลก็จะไม่ได้เก็บลงใน Shared Preferences นะ อันนี้อย่าลืมเด็ดขาด
ดังนั้นตอนนี้จะมีหัวใจสำคัญเป็นสามตัวแล้วนะ นั่นก็คือ Name, Keyword และ Commit
โดยคำสั่งสำหรับ Put ข้อมูลเพื่อเตรียมเก็บลงใน Shared Preferences จะมีคำสั่งทั้งหมดดังนี้
สำหรับ Shared Preferences จะสามารถเก็บข้อมูลได้หลายๆตัวตามแต่จะต้องการเลย เพราะงั้นต่อให้มีตัวแปรเป็นร้อยเป็นพัน ถ้าอยากจะเก็บไว้ในนี้ก็ทำได้หมด
จะเห็นว่า Commit แค่ครั้งสุดท้ายก็พอ แล้วข้อมูลทั้งหมดก็จะถูกเก็บไว้ให้ทันที
และให้จำไว้เสมอว่าจะเรียกใช้ที่ไหนก็ได้ ไม่มีตายตัว อย่ายึดติดกับรูปแบบ ให้สนใจว่าแอปพลิเคชันควรจะเก็บข้อมูลตอนไหนจึงจะเหมาะสม ดังนั้นอยากจะเก็บข้อมูลเมื่อไรก็เรียกใช้ Shared Preferences ได้เลย
ถ้าเรียกใช้บ่อยมากจะประกาศไว้เป็น Global ไปเลยก็ได้เหมือนกันนะ
การอ่านข้อมูลจาก Shared Preferences
มีการบันทึกข้อมูลก็ย่อมต้องมีการอ่านข้อมูล อย่างที่บอกในตอนแรกว่าถ้าจะดึงข้อมูลจาก Shared Preferences มาใช้ ก็สามารถเรียกผ่านคลาส Shared Preferences ได้เลย
ค่าที่ได้จะมีค่าเป็นเท่าไร?
ถ้าผู้ที่หลงเข้ามาอ่านคนใดตอบว่า -1 ให้เอามือเขกหัวหนึ่งทีนะครับ เพราะว่าถูกแค่ครึ่งเดียว (ถ้าใครตอบถูกก็เอามือเขกหัวสองที) คำตอบคือ "ขึ้นอยู่กับว่า userId ที่อยู่ใน Shared Preferences เก็บค่าอะไรไว้อยู่ก็เป็นค่านั้นๆ แต่ถ้าไม่มีข้อมูลของ userId อยู่ ก็จะมีค่าเป็น -1 แทน
ดังนั้น -1 ในกรณีนี้ก็มีไว้เผื่อว่าไม่มีข้อมูลจาก Keyword ดังกล่าวอยู่ใน Shared Preferences ก็จะกำหนดเป็น -1 แทน ซึ่งสามารถกำหนดได้ตามใจชอบว่าถ้าไม่มีจะให้เป็นอะไร ซึ่งตัวนี้จะเรียกกันว่า Default Value
โดยคำสั่งอ่านข้อมูลจาก Shared Preferences จะมีด้วยกันทั้งหมดดังนี้
ถ้านอกเหนือจากนี้ก็เสียใจด้วยนะ เพราะว่ามันเกิดมาเพื่อเก็บข้อมูลจากตัวแปรเท่านั้น
การเรียกใช้งานจะมีหลักการอยู่ง่ายๆคือ อยากจะใช้ก็เรียก Shared Preferences ก่อนแล้วค่อยดึงข้อมูล และถ้าอยากจะเก็บข้อมูลก็เรียก Shared Preferences Editor แล้วค่อยเก็บข้อมูลลงไป
• คลาส SharedPreferences : ดึงข้อมูลจาก Shared Preferences
• คลาส SharedPreferences.Editor : เก็บข้อมูลลงใน Shared Preferences
การเก็บข้อมูลลงใน Shared Preferences
ในการใช้งานเพื่อเก็บข้อมูลลงใน Shared Preferences ก็จะต้องเรียกจากคลาส SharedPreferences.Editor ดังนี้
SharedPreferences sp = getSharedPreferences(name, mode);
SharedPreferences.Editor editor = sp.edit();
ยกตัวอย่างเช่น
SharedPreferences sp = getSharedPreferences("PREF_NAME", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
โดยที่ PREF_NAME เป็นชื่อ Shared Preferences ที่ต้องการ ซึ่งเป็นชื่ออะไรก็ได้ เพราะมันจะไปกลายเป็นชื่อไฟล์ที่เก็บลงในเครื่อง เพราะงั้นถ้าจะดึงข้อมูลมาใช้งานก็เรียกชื่อไฟล์ให้ถูกด้วยล่ะ ส่วน Context.MODE_PRIVATE เป็นการกำหนดรูปแบบของการสร้างไฟล์ ซึ่งในที่นี้คือการสร้างไฟล์โดยให้ไฟล์นั้นสามารถเข้าถึงได้จากแอปพลิเคชันนี้เท่านั้น (หรือแอปพลิเคชันที่มี UID เหมือนกัน)
เพราะงั้นหัวใจหลักจะอยู่แค่ว่าจะกำหนดไฟล์ Shared Preferences เป็นชื่ออะไร จากนั้นเวลาจะเก็บข้อมูลก็ทำผ่าน editor สมมติว่าเจ้าของบล็อกอยากจะเก็บข้อมูลจากตัวแปร Integer ซักตัวก็จะได้แบบนี้
int x = 100;
SharedPreferences sp = getSharedPreferences("PREF_NAME", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putInt("My_Value", x);
editor.commit();
จะเห็นว่าการเก็บค่า Integer ลงใน Shared Preferences จะต้องมีการกำหนด Keyword ด้วย คล้ายๆกับการส่งข้อมูลระหว่าง Activity นั่นเอง โดยในตัวอย่างก็กำหนดให้เก็บข้อมูลลงไปโดยใช้ชื่อว่า My_Value ส่วนค่าที่เก็บก็คือค่าจากตัวแปร x ที่มีค่าเป็น 100 นั่นเอง ดังนั้น My_Value ก็จะเก็บ 100 ไว้ในนี้
และเมื่อกำหนดข้อมูลที่จะเก็บเสร็จแล้วก็ให้ใช้คำสั่ง Commit เพื่อทำการบันทึกข้อมูลลงใน Shared Preferences เพราะงั้นถ้าใช้คำสั่ง Put เยอะๆแล้วดันไม่ได้ใช้คำสั่ง Commit ต่อท้าย ข้อมูลก็จะไม่ได้เก็บลงใน Shared Preferences นะ อันนี้อย่าลืมเด็ดขาด
ดังนั้นตอนนี้จะมีหัวใจสำคัญเป็นสามตัวแล้วนะ นั่นก็คือ Name, Keyword และ Commit
โดยคำสั่งสำหรับ Put ข้อมูลเพื่อเตรียมเก็บลงใน Shared Preferences จะมีคำสั่งทั้งหมดดังนี้
void putBoolean(String key, boolean value);
void putInt(String key, int value);
void putFloat(String key, float value);
void putLong(String key, long value);
void putString(String key, String value);
void putStringSet(String key, Set<String> value);
สำหรับ Shared Preferences จะสามารถเก็บข้อมูลได้หลายๆตัวตามแต่จะต้องการเลย เพราะงั้นต่อให้มีตัวแปรเป็นร้อยเป็นพัน ถ้าอยากจะเก็บไว้ในนี้ก็ทำได้หมด
int x = 100;
boolean isFirstRun = false;
String user_name = "Sleeping For Less";
...
...
...
SharedPreferences sp = getSharedPreferences("PREF_NAME", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putInt("My_Value", x);
editor.putBoolean("IS_FIRST_RUN", isFirstRun );
editor.putString("USERNAME", user_name);
editor.putFloat("sampling_const", 10.59357752);
editor.commit();
จะเห็นว่า Commit แค่ครั้งสุดท้ายก็พอ แล้วข้อมูลทั้งหมดก็จะถูกเก็บไว้ให้ทันที
และให้จำไว้เสมอว่าจะเรียกใช้ที่ไหนก็ได้ ไม่มีตายตัว อย่ายึดติดกับรูปแบบ ให้สนใจว่าแอปพลิเคชันควรจะเก็บข้อมูลตอนไหนจึงจะเหมาะสม ดังนั้นอยากจะเก็บข้อมูลเมื่อไรก็เรียกใช้ Shared Preferences ได้เลย
final String P_NAME = "App_Config";
EditText edtUserName;
CheckBox cbRemember;
protected void onCreate(Bundle savedInstanceState) {
...
...
...
edtUserName = (EditText)findViewById(R.id.edtUserName);
cbRemember = (CheckBox)findViewById(R.id.cbRemember);
SharedPreferences sp = getSharedPreferences(P_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putBoolean("FirstRun", true);
editor.commit();
}
public void onPause() {
...
...
...
SharedPreferences sp = getSharedPreferences(P_NAME, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString("Username", edtUserName.getText().toString());
editor.putBoolean("RememberName", cbRemember.isChecked());
editor.commit();
}
ถ้าเรียกใช้บ่อยมากจะประกาศไว้เป็น Global ไปเลยก็ได้เหมือนกันนะ
final String P_NAME = "App_Config";
EditText edtUserName;
CheckBox cbRemember;
SharedPreferences sp;
SharedPreferences.Editor editor;
protected void onCreate(Bundle savedInstanceState) {
...
...
...
edtUserName = (EditText)findViewById(R.id.edtUserName);
cbRemember = (CheckBox)findViewById(R.id.cbRemember);
sp = getSharedPreferences(P_NAME, Context.MODE_PRIVATE);
editor = sp.edit();
editor.putBoolean("FirstRun", true);
editor.commit();
}
public void onPause() {
...
...
...
editor.putString("Username", edtUserName.getText().toString());
editor.putBoolean("RememberName", cbRemember.isChecked());
editor.commit();
}
การอ่านข้อมูลจาก Shared Preferences
มีการบันทึกข้อมูลก็ย่อมต้องมีการอ่านข้อมูล อย่างที่บอกในตอนแรกว่าถ้าจะดึงข้อมูลจาก Shared Preferences มาใช้ ก็สามารถเรียกผ่านคลาส Shared Preferences ได้เลย
SharedPreferences sp = getSharedPreferences("PREF_NAME", Context.MODE_PRIVATE);
int user_id = sp.getInt("userId", -1);
ค่าที่ได้จะมีค่าเป็นเท่าไร?
ถ้าผู้ที่หลงเข้ามาอ่านคนใดตอบว่า -1 ให้เอามือเขกหัวหนึ่งทีนะครับ เพราะว่าถูกแค่ครึ่งเดียว (ถ้าใครตอบถูกก็เอามือเขกหัวสองที) คำตอบคือ "ขึ้นอยู่กับว่า userId ที่อยู่ใน Shared Preferences เก็บค่าอะไรไว้อยู่ก็เป็นค่านั้นๆ แต่ถ้าไม่มีข้อมูลของ userId อยู่ ก็จะมีค่าเป็น -1 แทน
ดังนั้น -1 ในกรณีนี้ก็มีไว้เผื่อว่าไม่มีข้อมูลจาก Keyword ดังกล่าวอยู่ใน Shared Preferences ก็จะกำหนดเป็น -1 แทน ซึ่งสามารถกำหนดได้ตามใจชอบว่าถ้าไม่มีจะให้เป็นอะไร ซึ่งตัวนี้จะเรียกกันว่า Default Value
โดยคำสั่งอ่านข้อมูลจาก Shared Preferences จะมีด้วยกันทั้งหมดดังนี้
boolean getBoolean(String key, boolean defValue);
int getInt(String key, int defValue);
float getFloat(String key, float defValue);
long getLong(String key, long defValue);
String getString(String key, String defValue);
Set<String> getStringSet(String key, Set<String> defValue);
สำหรับการอ่านข้อมูลจาก Shared Preferences ก็จะคล้ายๆกับการบันทึกข้อมูล คือ เรียกใช้เมื่อไรก็ได้ ไม่ได้จำกัดตายตัว แต่จะต่างกันตรงที่ไม่ต้องมี Commit เพราะเป็นการดึงข้อมูลออกมาใช้งาน และที่สำคัญ กำหนดชื่อ Shared Preferences ที่ต้องการดึงข้อมูลให้ถูกต้อง แล้ว Keyword ก็ต้องถูกต้อง และกำหนด Default Value เผื่อไว้ในกรณีที่ไม่สามารถดึงข้อมูลออกมาได้ (ข้อมูลไม่มีอยู่หรือใส่ชื่อ Keyword ผิด)
และที่สำคัญคือคลาส SharedPreferences ที่ประกาศจะสามารถใช้ร่วมกันได้เลยไม่ว่าจะบันทึกข้อมูลหรืออ่านข้อมูลก็ตาม
ยกตัวอย่างการประยุกต์ใช้งานสุดคลาสสิค
Edit Text ที่ให้ผู้ใช้ใส่ User Name จะให้จำว่าล่าสุดผู้ใช้พิมพ์ลงไปว่าอะไร เพื่อที่ว่าเปิดใช้งานในครั้งต่อไปผู้ใช้จะได้ไม่ต้องพิมพ์ใหม่ทุกครั้งนั่นเอง
final String PREFNAME = "SamplePreferences";
final String USERNAME = "UserName";
EditText edtUserName;
SharedPreferences sp;
SharedPreferences.Editor editor;
protected void onCreate(Bundle savedInstanceState) {
...
...
...
sp = getSharedPreferences(PREFNAME, Context.MODE_PRIVATE);
editor = sp.edit();
edtUserName = (EditText)findViewById(R.id.edtUserName);
edtUserName.setText(sp.getString(USERNAME, ""));
edtUserName.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before, int count) { }
public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
public void afterTextChanged(Editable s) {
editor.putString(USERNAME, s.toString());
editor.commit();
}
});
...
...
...
}
จะเห็นว่าเจ้าของบล็อกสั่งให้เก็บชื่อผู้ใช้ที่พิมพ์ลงในช่อง edtUserName ทุกครั้งที่มีการเปลี่ยนแปลง (After Text Changed) และนำมากำหนดเมื่อ onCreate ทำงาน (Activity เริ่มทำงาน)
โดยจะเห็นว่าเจ้าของบล็อกใส่ Default Value ไว้เป็น "" ซึ่งก็คือข้อความว่างเปล่า (ไม่ใช่ Null นะ) นั่นก็หมายความว่าในตอนแรกสุดที่แอปพลิเคชันถูกเปิดขึ้นมาครั้งแรกจะไม่มีข้อมูลที่ชื่อ UserName อยู่ใน Shared Preferences จึงกำหนดให้เป็น "" หรือก็คือไม่มีข้อความนั่นเอง
และเมื่อผู้ใช้เริ่มพิมพ์ในช่องชื่อผู้ใช้ก็จะค่อยๆเก็บข้อมูลเรื่อยๆ เพื่อนำมาใช้ในการกำหนดค่าให้กับ edtUserName เมื่อเปิดใช้งานในครั้งต่อไปนั่นเอง
เพิ่มปุ่ม Remember เข้าไปซักหน่อยดีมั้ยนะ?
การเพิ่มปุ่ม Remember มักจะเป็นแอปพลิเคชันที่ต้องการให้ผู้ใช้ล็อกอินใหม่ทุกครั้งที่ใช้งาน (เน้น Security) โดยจะมี Checkbox ยอดนิยมอย่าง Remember Username ให้เลือก ถ้าเลือกที่ช่องนี้เมื่อใช้งานครั้งต่อไปก็จะไม่ต้องพิมพ์ Username ใหม่ (พิมพ์แค่ Password) ดังนั้นก็จะต้องมีการใช้ Shared Preferences ที่ซับซ้อนจากเดิมนิดหน่อย ดังนี้
final String PREF_NAME = "LoginPreferences";
final String KEY_USERNAME = "Username";
final String KEY_REMEMBER = "RememberUsername";
SharedPreferences sp;
SharedPreferences.Editor editor;
EditText edtUsername;
CheckBox cbRemember;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
sp = getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
editor = sp.edit();
edtUsername = (EditText)findViewById(R.id.edtUsername);
edtUsername.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before, int count) { }
public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
public void afterTextChanged(Editable s) {
editor = sp.edit();
editor.putString(KEY_USERNAME, s.toString());
editor.commit();
}
});
cbRemember = (CheckBox)findViewById(R.id.cbRemember);
cbRemember.setOnCheckedChangeListener(new OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
editor.putBoolean(KEY_REMEMBER, isChecked);
editor.commit();
}
});
boolean isRemember = sp.getBoolean(KEY_REMEMBER, false);
cbRemember.setChecked(isRemember);
if(isRemember) {
String username = sp.getString(KEY_USERNAME, "");
edtUsername.setText(username);
}
}
นอกจาก Commit แล้วยังมี Apply อีกด้วยนะ
ถ้าผู้ที่หลงเข้ามาอ่านที่เคยศึกษาจากที่อื่นก็อาจจะเห็นบางทีใช้คำสั่ง Apply แทน Commit (แตส่วนใหญ่ก็มักจะใช้ Commit) ซึ่งทั้งสองคำสั่งนี้ให้ผลเหมือนกันคือบันทึกข้อมูลลงใน Shared Preferences แต่ทว่าจะแตกต่างกันดังนี้
Apply เป็นการบันทึกข้อมูลแบบ Asynchronous โดยไม่สนใจว่าข้อมูลบันทึกได้สำเร็จหรือไม่
Commit เป็นการบันทึกข้อมูลแบบ Synchronous ซึ่งจะสามารถรู้ได้ว่าข้อมูลบันทึกสำเร็จหรือป่าว
ถ้าสังเกตดีๆจะเห็นว่าคำสั่ง Commit จะมี Return เป็น Boolean ด้วย ซึ่งบอกว่าบันทึกไฟล์สำเร็จหรือไม่ แต่ในขณะที่ Apply นั้นจะไม่มี Return ซึ่งทำให้ตรวจสอบไม่ได้นั่นเอง
ถ้าสร้าง Shared Preferences สองตัวแต่ Preferences Name ตัวเดียวกัน แล้ว Commit พร้อมกันล่ะ?
อันนี้เป็นคำถามเชิงขบคิดเล็กน้อย สมมติว่าสร้าง sp1 และ sp2 ขึ้นมา แต่กำหนดชื่อ Preferences Name เหมือนๆกัน ก็จะสามารถใช้งานได้ปกติ แต่ถ้าดันพิเรณท์ไปสั่ง Commit ที่ sp1 กับ sp2 ในเวลาใกล้เคียงกัน ผลที่ได้ก็คือตัวที่เรียก Commit ทีหลังจะบันทึกข้อมูลได้สำเร็จ ส่วนตัวแรกจะบันทึกข้อมูลไม่สำเร็จ และคำสั่ง Apply ก็ให้ผลลัพธ์แบบเดียวกัน
สามารถเข้าไปดูข้อมูลที่เก็บไว้ในนั้นได้ที่ไหน?
สำหรับผู้ที่หลงเข้ามาอ่านที่ต้องการเช็คข้อมูลที่เก็บไว้ในนั้นว่ามีอะไรบ้าง มีค่าเป็นอะไร และถูกต้องหรือไม่ ก็สามารถเช็คผ่านคำสั่งโปรแกรมได้เหมือนกัน เพราะในคลาส SharedPreferences จะมีคำสั่ง getAll ที่ Return ออกมาเป็น Map<String, ?> แล้วเอาไปแสดงเพื่อเช็คดูก็ได้
ถ้าอยากได้วิธีง่ายๆแบบไม่ต้องเขียนโคีดก็มีอยู่เหมือนกัน แต่อุปกรณ์แอนดรอยด์ต้องรูทให้เรียบร้อยซะก่อนนะ เนื่องจากข้อมูลดังกล่าวอยู่ในส่วนที่เรียกว่า Internal Storage ของแอปพลิเคชันนั้นๆ ดังนั้นถ้ารูทเครื่องก็จะสามารถเปิดเข้าไปดูใน Directory นั้นๆได้ โดยตัวอย่างนี้เจ้าของบล็อกใช้ ES File Explorer เพื่อเปิดเข้าไปดู (ต้อง Root Access ก่อนนะ) โดยข้อมูลดังกล่าวจะอยู่ที่
/data/data/package_name/shared_prefs/
โดยที่ package_name ก็ขึ้นอยู่กับชื่อ Package ของแอปพลิเคชันตัวนั้นๆ
หมายเหตุ : ไม่ใช่ /sdcard/data/data/package_name/shared_prefs/ นะ
เมื่อเปิดเข้าไปดูก็จะเห็นข้อมูลที่เป็นไฟล์ XML อยู่ในนั้น ที่มีข้อมูลเก็บไว้อยู่ในนี้ ซึ่งเกิดมาจากการที่เจ้าของบล็อกเขียนคำสั่งให้เก็บข้อมูลลงใน Shared Preferences นั่นเอง
และชื่อไฟล์ก็จะมาจากการกำหนด Preferences Name นั่นเอง จึงสามารถประยุกต์สร้างเป็นหลายๆไฟล์เพื่อเก็บข้อมูลให้เป็นสัดส่วนก็ได้ ซึ่งในแอปพลิเคชันที่มีโครงสร้างที่ใหญ่ก็มักจะเก็บข้อมูลลงใน Shared Preferences แยกไฟล์กันเพื่อให้จัดการได้ง่ายๆ
ยกตัวอย่างเช่น Shared Perferences ของเกม Thapster
ซึ่ง Shared Preferences นี่แหละ ที่เกมหลายๆเกมเค้าใช้กันเวลาเก็บข้อมูลจากการเล่นเกม เช่น High Score หรือเงินของตัวละครในเกมเป็นต้น จึงทำให้สามารถโกงเกมได้ง่ายๆ เพียงแค่รูทเครื่องแล้วเข้าไปแก้ไขข้อมูลในนี้นั่นเอง ดังนั้นถ้าเป็นข้อมูลที่สำคัญมากๆ ห้ามเก็บด้วยวิธีนี้เด็ดขาด เช่น Password ของผู้ใช้ เป็นต้น
จงเอาไปประยุกต์ใช้กันให้เพลิดเพลินนะครับ