มีใครเคยนำข้อมูลที่เยอะ ๆ โยนข้าม Activity บ้างไม๊ครับ รวมถึงการ Save/Restore State ด้วยนะ ถ้าเคยทำ ก็จะรู้ว่า ต้องมาเขียนคำสั่งเพื่อเก็บข้อมูลลง Bundle
หรือ Intent
ก่อน ด้วย Method put ทั้งหลาย ก่อนจะส่งข้อมูลไป ซึ่งจะมีชนิดตัวแปรมากมายให้เราเลือกใช้ แต่ว่ามันไม่สามารถที่จะ put Object ลงไปได้…
ถ้าอยากจะส่ง Object สามารถทำได้ด้วยการทำ Serialization นั่นเอง ซึ่งใน Bundle
และ Intent
จะสามารถ put ได้ 2 ชนิด ก็คือ Serializable
และ Parcelable
ซึ่งทั้งคู่ เป็น Interface นั่นหมายความว่า เราต้อง Implement Interface ไปยัง Class ก่อน ถึงจะใช้งานได้
สำหรับบน Android นั้น Parcelable
เป็นวิธีที่จะทำ Serialize และ Deserialize ซึ่งทำงานได้เร็วกว่าวิธีอื่น ๆ ถึง 10 เท่า!! ถ้าอย่างงั้นแล้วจะรออะไรอีก ไป Implement Interface Parcelable
กันเถอะครับ
Code ด้านล่างนี้ เป็นตัวอย่างการ Implement Interface Parcelable
จาก Android Developer Reference จะเห็นว่า การใช้ Parcelable
นั้น มีความยุ่งยากพอสมควร เพราะต้อง Implement Method writeToParcel()
, createFromParcel()
และ Inner Class CREATOR
ที่ Implement Interface Parcelable.Creator<T>
ด้วย ตามที่ได้ไฮไลท์ไว้ใน Code ด้านล่าง เพื่อที่จะเก็บค่าตัวแปรลงไปยัง Class Parcel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
public class MyParcelable implements Parcelable { private int mData; public int describeContents() { return 0; } public void writeToParcel(Parcel out, int flags) { out.writeInt(mData); } public static final Parcelable.Creator<MyParcelable> CREATOR = new Parcelable.Creator<MyParcelable>() { public MyParcelable createFromParcel(Parcel in) { return new MyParcelable(in); } public MyParcelable[] newArray(int size) { return new MyParcelable[size]; } }; private MyParcelable(Parcel in) { mData = in.readInt(); } } |
แต่เดี๋ยวก่อน~!! ถ้าอยากเก็บ Object ลง Parcel
ตรง ๆ ก็ยังทำไม่ได้นะ ทำได้แต่ตัวแปรธรรมดา ถ้าอยากเก็บ Object ลงไป ต้อง Implement Interface IBinder
ก่อน ถึงจะยัดลงไปได้
ปวดหัวกันแล้วใช่ไม๊ครับ กว่าจะยัด Object ลงไปได้ ไม่ใช่เรื่องเล่น ๆ
งั้นเอาใหม่… ถ้าเราสามารถยัด Object ลง Bundle
หรือ Intent
โดยสามารถเขียนคำสั่งให้จบได้ภายใน 1 บรรทัด เอาม๊า ๆ
เชิญตามมาทางนี้ครับ ผมขอแนะนำ Parceler Library ที่จะช่วยให้การสร้าง Parcelable
นั้น เป็นเรื่องง่าย ๆ
List of contents
How to use Parceler
ก่อนอื่น ต้องทำการเพิ่ม Library ให้กับ Project ของเราซะก่อน สำหรับ Android Studio นั้น สามารถเพิ่ม Dependency ใน build.gradle ของ Module app เรา ดังนี้
1 2 |
compile "org.parceler:parceler-api:1.0.2" apt "org.parceler:parceler:1.0.2" |
แล้วทำการ Sync ให้เรียบร้อย เป็นอันว่า ใช้ Parceler ได้แล้ว
ตรวจสอบ Version ล่าสุดของ Parceler Library ได้ที่ http://parceler.org/
Annotation
สำหรับ Parceler นั้น จะให้เราระบุ Annotation @Parcel
ไว้ที่ Class ที่เราจะใช้เก็บข้อมูล
Class ด้านล่างนี้ ผมออกแบบให้เก็บข้อมูล 3 ตัวด้วยกัน คือ fullname, gender และ age โดยจะใช้ Constructor ในการรับข้อมูลเข้ามา และมี Getter Method สำหรับอ่านค่าออกไป ดังนี้
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
@Parcel public class Person { public enum Gender { MALE, FEMALE } private String fullname; private Gender gender; private int age; public Person(String fullname, Gender gender, int age) { this.fullname = fullname; this.gender = gender; this.age = age; } public String getFullname() { return fullname; } public Gender getGender() { return gender; } public int getAge() {<span id="transmark"></span> return age; } } |
ลอง Build ดู จะพบกับ Error ดังนี้

สาเหตุก็เนื่องมาจาก Parceler หา Annotation @ParcelConstructor
และ Default Constructor ไม่เจอ ก็แก้ไขได้ 2 วิธี ก็คือ แปะ Annotation @ParcelConstructor
ที่ Constructor ของเรา ดังนี้
1 2 3 4 5 6 |
@ParcelConstructor public Person(String fullname, Gender gender, int age) { this.fullname = fullname; this.gender = gender; this.age = age; } |
หรือว่าจะสร้าง Default Constructor เปล่า ๆ ขึ้นมาก็ได้ ดังนี้
1 |
public Person() { /* Required empty bean constructor */ } |
คราวนี้ลอง Build ดูใหม่ จะพบกับ Warning แทน ดังนี้

คราวนี้แค่เตือนเฉย ๆ สิ่งที่เตือนคือ ห้ามประกาศ Field เป็น Private เพราะฉะนั้นก็ลบทิ้งโลด
1 2 3 |
String fullname; Gender gender; int age; |
สุดท้ายก็จะได้ Class ที่แปะ Annotation @Parcel
พร้อมใช้งานกับ Paceler แล้ว
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
@Parcel public class Person { public enum Gender { MALE, FEMALE } String fullname; Gender gender; int age; public Person() { /* Required empty bean constructor */ } public Person(String fullname, Gender gender, int age) { this.fullname = fullname; this.gender = gender; this.age = age; } public String getFullname() { return fullname; } public Gender getGender() { return gender; } public int getAge() { return age; } } |
Wrap
Wrap ก็คือการใช้ Parceler ทำการ “ห่อ” Object ไว้ ก่อนอื่นขอสร้าง Object จาก Class Person ที่สร้างไว้ก่อน
1 |
Person person = new Person("Artit Kiuwilai", Person.Gender.MALE, 18); |
เมื่อได้ Object มาแล้ว ก็จัดการ Wrap ซะ Method wrap()
ของ Class Parcels
ก็จะได้ Parcelable
ออกมา ด้วยคำสั่งดังนี้
1 |
Parcelable wrapped = Parcels.wrap(person); |
ง่ายมะ ๆ
Unwrap
เมื่อห่อแล้ว ก็ต้องมีการ “แกะห่อ” โดยเราจะใช้ Method unwrap()
ของ Class Parcels
ดังนี้
1 |
Person person = Parcels.unwrap(wrapped); |
ก็จะได้ Object กลับคืนมาแล้วววววววววว
ลอง get ข้อมูลออกมาจาก Object ดู ก็จะได้ข้อมูลเหมือนเดิมเป๊ะ ๆ เด๊ะ ๆ
1 2 3 |
person.getFullname(); // "Artit Kiuwilai" person.getGender(); // Person.Gender.MALE person.getAge(); // 18 |
ง่ายอีกแล้วเน๊อะ~!!
Add to Bundle
คราวนี้เราลองเอามาใช้กับ Bundle
ดูบ้าง โดยจุดที่เราจะได้ใช้ Bundle
บ่อย ๆ เลยนั่นก็คือเรื่องของการ Save/Restore State กันบ้าง…
ในการ Save State บน Method onSaveInstanceState()
นั้น จะมี Parameter ชนิด Bundle
ส่งมาให้เราด้วย เราสามารถใช้ Method putParcelable()
ของ Bundle
ในการเก็บ “ห่อ” ของ Object ได้ดังนี้
1 2 3 4 5 6 |
@Override protected void onSaveInstanceState(Bundle outState) { outState.putParcelable("person key", Parcels.wrap(person)); super.onSaveInstanceState(outState); } |
ส่วนการ Restore State บน Method onRestoreInstanceState()
ก็จะมี Bundle
ส่งมาให้เช่นกัน ก็ใช้ Method getParcelable()
ของ Bundle
ในการนำ “ห่อ” ของ Object ออกมาได้
1 2 3 4 5 6 |
@Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); person = Parcels.unwrap(savedInstanceState.getParcelable("person key")); } |
หรือจะทำบน Method onCreate()
ก็ได้เหมือนกัน
Add to Intent
สำหรับการใช้งานกับ Intent
ซึ่งโดยส่วนใหญ่เราจะใช้ฝากข้อมูล เพื่อส่งข้าม Activity นั่นเอง
การเก็บ Parcelable
ลง Intent
ก็แค่เรียกใช้งาน Method putExtra()
ของ Intent
ก็สามารถเก็บ “ห่อ” ของ Object ลงไปได้แล้ว
1 2 3 |
Intent intent = new Intent(); intent.putExtra("person key", Parcels.wrap(person)); |
ส่วนการนำ “ห่อ” ของ Object ออกมาจาก Intent
ก็สามารถใช้ Method getParcelableExtra()
ของ Intent
ในการนำ “ห่อ” ของ Object ออกมา
1 2 3 |
Intent intent = getIntent(); Person person = Parcels.unwrap(intent.getParcelableExtra("person key")); |
เราก็สามารถใช้ Parceler ร่วมกับ Intent
ได้แล้ว
Configuring Proguard
สำหรับการเปิดใช้งาน Proguard จะต้องกำหนดในไฟล์ Proguard เพิ่มดังนี้
1 2 3 4 5 6 |
# Parcel library -keep class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator *; } -keep class org.parceler.Parceler$$Parcels |
สำหรับการใช้งาน Parceler Library แบบอื่น ๆ และการใช้งานที่ Advance กว่านี้ สามารถศึกษาต่อได้จากที่ http://parceler.org/
ส่วน Code ตัวอย่างในบทความนี้ ผมนำไปเขียนเป็น App ตัวอย่าง โดยจะมีการนำ Parceler ร่วมกับ Bundle
ในการทำเรื่อง Save/Restore State และการนำ Parceler ร่วมกับ Intent
ในการส่งข้อมูลข้าม Activity ทั้งไปและกลับ ลองไปดู Code กันต่อที่ Project ของผม บน GitHub นะครับ
Permalink
Permalink
Permalink