29 April 2013

ว่าด้วยเรื่อง Context

Updated on

Context เป็นคลาสตัวหนึ่งที่ผู้ที่หลงเข้ามาอ่านหลายคนคุ้นตากัน
โดยเฉพาะการเรียกใช้คลาสหลายๆคลาสที่เวลากำหนดค่านั่นแหละ
ซึ่งจะใช้สำหรับติดต่อใช้คำสั่งของแอปพลิเคชันนั้นๆ
และรวมไปถึงการระบุเรียกใช้ Global Variable ของคลาสนั้นๆด้วย


เช่น getPackageName() ฟังก์ชันที่ดึง Package Name เป็น String
หรือคำสั่ง setTitle(String) ที่ใช้กำหนดชื่อ Label ของแอปฯนั้นๆ

แต่ทีนี้ Context สามารถประกาศเรียกได้หลายๆแบบด้วยกัน



• เรียกคำสั่งทันที โดยสามารถทำได้อยู่แล้ว และ Context ดังกล่าว
ก็จะอิงจาก Activity ที่ชื่อ Main นั่นเอง (อยู่ที่ตำแหน่งของคำสั่ง)

• เรียกคำสั่งโดยระบุจาก this ก่อน ซึ่ง this เป็นคำสั่งที่เอาไว้ระบุ
แบบเจาะจงเพื่อ แต่ว่าจะอิงจากบรรทัดที่เรียกใช้ ว่าอยู่ในไหน

• เรียกคำสั่งโดยระบุจาก Main.this ซึ่ง Main ก็คือชื่อ Activity
วิธีนี้จะเป็นการระบุที่เจาะจงมากกว่าการใช้ this เฉยๆ
คือระบุไปโดยตรงเลยว่าใช้ Context ที่มาจาก Main

• การเรียกใช้คำสั่งเพื่อดึง Context ของ Application โดยตรง

ซึ่งเอาจริงๆแล้ว พวกนี้ก็คือ Context เหมือนกันนั่นแหละ
แต่ความต่างกันก็คือวิธีในการเรียก และตำแหน่งของคำสั่งที่เรียก



โดยส่วนตัวเจ้าของบล็อกก็ไม่อยากให้เจาะลึกกับมันมากนัก
ส่วนนึงก็เพราะว่าเจ้าของบล็อกนึกคำอธิบายคลาสนี้ไม่ค่อยออก
เอาจริงๆแล้วหัวใจสำคัญของมันอยู่ที่ตอนเรียกใช้งานมากกว่า

เพราะหลายๆคลาสเวลาประกาศจะต้องกำหนดค่า Context ด้วย
ดังนั้น Context ที่เอามากำหนดส่วนใหญ่ก็จะมาจาก Application


จากตัวอย่างดังกล่าวก็คือประกาศ GridView และกำหนด Context ลงไป
ก็จะเห็นว่าการเรียก Context ทั้ง 3 วิธี สามารถกำหนดค่าได้เหมือนกัน

ทีนี้มาดูจุดที่ผิดกันบ้าง ผู้ที่หลงเข้ามาอ่านหลายคนอาจจะเคยเจอ


จากภาพข้างบนจะเห็นว่าเข้าของบล็อกประกาศ GridView สองที่
ตัวแรกประกาศไว้ใน onCreate ของ Main สามารถทำงานได้ปกติ
แต่ว่าอีกตัวเจ้าของบล็อกประกาศไว้ใน OnClickListener แทน
และจะเห็นว่า Eclipse ได้เตือนเออเรอว่าไม่สามารถใช้ this ได้

this เป็นคำสั่งที่ดึง Context จากที่ที่ตัวมันเองอยู่ ณ ตอนนั้น
การเรียกใช้ในฟังก์ชัน onCreate ก็จะดึง Context จากคลาส Activity
แต่ตอนนี้ this อยู่ที่คลาส OnClickListener ซึ่งไม่มี Context ส่งกลับมาให้
จึงทำให้เกิดเออเรอขึ้นมาเพราะว่าดึง Context จาก onClickListener ไม่ได้

ดังนั้นการใช้ this จะต้องดูด้วยว่าเรียกใช้ที่ไหนของโปรแกรม
ถึงแม้ว่า OnClickListener จะอยู่ในคลาส Activity ก็จริง
แต่ว่า this จะมองจากที่ที่ตัวมันเองอยู่ ก็คือ OnClickListener
(เพราะโดยปกติ Activity กับ Listener ทำงานแยกกันอยู่แล้ว)

ดังนั้นถ้าจะใช้ this อย่างเดียวไม่ได้ ก็ให้ระบุชื่อ Activity ด้วย


วิธีนี้จะเป็นการระบุๆไปตรงๆเลยว่า this ที่เรียกมาจาก Main
และเนื่องจาก Main เป็นคลาส Activity อยู่แล้ว ก็ดึง Context ได้
(อย่าลืมล่ะว่าวิธีนี้ อิงตาม Main.java ถ้าไม่ใช้ Main ก็เปลี่ยนตามด้ว
เช่น ถ้าใช้ใน ShowData.java ก็ต้องเปลี่ยนเป็น ShowData.this ด้วย)

หรืออีกวิธีหนึ่งก็คือใช้ getApplicationContext() ไปเลยชัวร์สุด
เพราะว่าจะเป็นคำสั่งที่ใช้ดึง Context จาก Application  โดยตรง
ไม่ต้องมานั่งระบุชื่่อของ Activity ที่เรียกใช้งานอีกด้วย


แต่วิธีนี้ติดแค่ปัญหาเดียวคือ พิมยาวกว่าชาวบ้านเค้า
เนื่องจากเจ้าของบล็อกต้องเขียนโค๊ดอธิบายในบทความ
บางทีคำสั่งนี้มันทำให้โค๊ดยาวเกินไปต้องตัดบรรทัดใหม่ 555
แต่วิํธีนี้ก็ง่ายดีเพราะไม่ต้องสนใจว่าอยู่ใน Activity อะไร

ดังนั้นก็สรุปคราวๆก็ดูรูปข้างล่างเอาละกัน
ว่าแบบไหนใช้ได้แบบไหนใช้ไม่ได้บ้าง


สำหรับคลาสที่ดึง Context ได้บ้างไม่ได้บ้าง 
ส่วนมากจะเป็นคลาสที่เกี่ยวกับการทำงานของ Thread 
เช่น Activity, Thread, Listener หรือ Handler เป็นต้น
อยากรู้เพิ่มเติมก็ต้องไปศึกษาดูกันเองนะครับ