Categories

วันศุกร์ที่ 10 กรกฎาคม พ.ศ. 2552

Android Application Fundamentals

Activities Activity คือหน้า UI ที่ user กระทำการต่าง ๆ บนนั้น อาจจะเป็นการแสดงเมนูให้เลือก, แสดงรูปภาพพร้อมคำอธิบาย, อะไรก็ตาม ฯลฯ โปรแกรม text โปรแกรมหนึ่งอาจจะมี activity นึงที่ใช้แสดงเบอร์ที่จะส่งไป และมี activity ที่สองที่จะเขียนข้อความที่จะส่ง และอีก activity ไว้ดูข้อความก่อนหน้านั้น หรือเอาไว้แก้ setting ซึ่งถึงแม้มันจะทำงานร่วมกันในหน้า UI หน้าเดียว แต่ activity แต่ละตัวก็ไม่ขึ้นต่อกัน และทุกตัวเชียนขึ้นโดนเป็น sub class ของ Class Activity โปรแกรมเราอาจจะมี 1 activity หรือหลาย Activity ก็ได้แล้วแต่เราออกแบบ แต่ปกติแล้วจะมี Activity นึงที่เป็นหน้าแรกที่ user เห็นตอนเปิดโปรแกรมเราเข้ามา การเปลี่ยน Activity นึง ไปอีก Activity นึง ใช้การเรียก Activity จาก Activity ก่อนหน้า ทุก Activity จะมีพื้นที่ให้ใส่อะไรลงไปข้างใน ปกติแล้วจะเต็มจอ แต่ถ้าอยากเปลี่ยนก็ปรับขนาดได้เอง หรือปรับให้อยู่บนหน้าต่างอื่นก็ได้ Activity สามารถสร้างหน้าต่างอื่นเพิ่มได้ เช่น pop up หรือหน้าต่างแสดงข้อมูลพื้นฐานเวลา user เลือกไปที่วัตถุ ๆ หนึ่งบนจอ เนื้อหาที่แสดงบนจอมาจาก Class View และ มันจะเป็นส่วนที่ติดต่อกับผู้ใช้ เช่น อาจจะแสดงรูปเล็กๆบนจอ พอเอานิ้วกดแล้วขยายรูปเต็มเป็นต้น View จะถูกวางไว้ใน Activity ด้วยคำสั่ง Activity.setContentView() Services Services ไม่มี ีuser interface แต่จะทำงานที่ background แทน ในช่วงเวลาหนึ่งๆ แล้วแต่กำหนด เช่น มี service อันนึงเล่นเพลงเป็น background ระหว่างที่ผู้ใช้งานก็ใช้งานอย่างอื่นไปด้วย หรืออาจจะเป็น service ที่ไปดึงข้อมูลจากที่อื่นใน network หรือคำนวณอะไรบางอย่างข้างหลัง และส่งค่ากลับมาให้ Activity ที่ต้องการใช้ Service ทุกตัวสืบทอดมาจาก Class Service ตัวอย่างที่ดีที่สุดอันหนึ่งคือโปรแกรมเล่นเพลง โปรแกรมนี้จะประกอบด้วย Activity 1 หรือ 2 อันที่ให้ User เลือกเพลงกับสั่งเล่นเพลง อย่างไรก็ตาม ตัวที่จะไปเล่นเพลงจริงๆนั้นไม่ควรถูกจัดการด้วย Activity เพราะผู้ใช้น่าจะหวังไว้ว่าเพลงจะยังเล่นต่อไปในระหว่างที่เขาไปทำอย่างอื่น เพื่อที่จะให้เพลงยังเล่นต่อไปได้ Activity จะไปเรียก Service ให้ทำงานอยู่ใน background และระบบจะยังคงเก็บ Service นี้ให้ทำงานต่อ แม้ว่า Activity ที่เรียกมันจะถูกปิดไปแล้ว เรายังสามารถที่จะติดต่อกับ Service ที่กำลังทำงานอยู่ได้ด้วย ซึ่งระหว่างที่ติดต่อนั้น เราก็จะสามารถสั่งการ Service นั้น ตามแต่ที่ Service นั้นจะได้เขียนไว้ให้ทำได้ เช่นกับ Service ที่เล่นเพลง เราก็สามารถ หยุด ย้อนกลับ หรือเล่นเพลงใหม่ได้ เช่นเดียวกันกับ Activity และ component อื่นๆ Services ทำงานใน main thread ของ application process มันจึงไม่ไป block component อื่น หรือ User interface แต่มันมักจะสร้าง thread ใหม่ เพื่อใช้สำหรับงานที่กินเวลามากๆ อย่างเช่น การเล่นเพลง Broadcast receivers ไม่ทำอะไรเลยนอกจาก รับ แล้วก็ตอบสนองต่อ broadcast announcement ซึ่ง boardcast ส่วนใหญ่มักมาจากโคดของระบบ เช่น ประกาศ time zone ถูกเปลี่ยน, แบตต่ำ, รูปถูกรับ หรือเปลี่ยนภาษา นอกจากนั้น โปรแกรมของเราก็สร้าง boardcasts ได้ เช่นบอกให้โปรแกรมอื่นรู้ว่าข้อมูลได้ดาวน์โหลดเสร็จแล้ว และพร้อมให้พวกมันใช้งาน โปรแกรมหนึ่งๆ จะมีกี่ broadcast receiver ก็ได้ เพื่อตอบสนองต่อสิ่งที่มันสนใจ receivers ทุกตัวสืบทอดคลาส BroadcastReceiver Broadcast receivers ไม่มี UI แต่มันสามารถไปเรียก Activity เพื่อตอบสนองสิ่งที่มันได้รับมาได้ หรือมันอาจจะใช้ NotificationManager เพื่อเตือนผู้ใช้ ซึ่ง Notification สามารถเรียกร้องความสนใจได้หลายแบบ เช่น แสง backlight, สั่น, เล่นเสียง เป็นต้น และมันมักจะวาง icon ไว้บน status bar เพื่อให้ user เปิดเข้าไปอ่านได้ Content providers content provider สร้างเซ็ทข้อมูลของโปรแกรมหนึ่งๆขึ้นมา เพื่อให้โปรแกรมอื่นสามารถเอาไปใช้งานได้ อาจจะเป็นไฟล์ หรือ SQLite หรืออย่างอื่นที่มัน makes sense สืบทอดจากคลาส ContentProvider ที่ให้โปรแกรมอื่นดึงข้อมูล และเก็บข้อมูลนั้นไว้ในแบบที่ตนต้องการ แต่เราไม่ได้เรียก method นั้นตรง ๆ เราจะใช้ object ContentResolver ไปเรียก method นั้นแทน ContentResolver สามารถคุยกับ content provider ได้ทุกตัว มันทำงานร่วมกันกับ provider เพื่อติดต่อสื่อสารระหว่าง provider ด้วยกัน Activating components: intents Content provider ทำงานตอนที่โดน ContentResolver ส่ง request มา แต่อีก 3 ตัว activities, services, and broadcast receivers จะทำงานด้วย asynchronous messages ที่เรียกว่า intents ซึ่งเป็น object ของ Intent ที่เก็บเนื้อหาของ messege นั้นๆ สำหรับ activities และ services จะมีชื่อของ action ที่ถูกร้องขอ และ URI ของข้อมูลที่จะไปทำงานด้วย ตัวอย่างเช่น เราจะส่ง request อันนึงไปยัง activity เพื่อแสดงรูปภาพให้เห็น และยังให้สามารถเพิ่มคำอธิบายได้ สำหรับ boardcast receivers นั้น Intent object เก็บชื่อ action ที่จะถูกประกาศ เช่นมันจะประกาศข้อความเตือนเมื่อกดปุ่มถ่ายรูป การจะเรียก component มันก็จะมีวิธีต่างๆกัน Activity จะถูกเปิดโดยการส่ง Intent object ไปยัง Context.startActivity() หรือ Activity.startActivityForResult() แล้ว activity ที่ถูกสร้างขึ้นจะสามารถดู Intent ที่เรียกมันขึ้นมาได้ด้วย method getIntent() และ Android จะเรียก method ของ activity ชื่อ onNewIntent() เพื่อส่ง intent ให้มัน Activity นึงมักจะเรียกอีก Activity นึง แต่ถ้าอยากให้ result กลับมายัง Activity ที่เรียกมัน จะใช้คำสั่ง startActivityForResult() แทน startActivity() เช่นตอน User เลือกรูปภาพ ผลลัพธ์จะถูกส่งกลับไปยัง Intent ที่เรียกมันด้วย method onActivityResult Service ถูกสร้างโดยส่ง Intent obkect ไปยัง Context.startService() Android จะเรียก method ของ service ชื่อ onStart() เพื่อส่ง Intent object ให้มัน ในทำนองเดียวกัน intent สามารถส่ง Context.bindService() เพื่อติดต่อระหว่าง component ที่ถูกเรียกอยู่ ไปยัง service เป้าหมาย service ก็จะรับ Intent object ด้วยคำสั่ง onBind() ถ้า service ไม่ได้ทำงานอยู่ ใช้คำสั่ง bindService() จะเปิดมันให้ ตัวอย่างเช่น มี activity ที่จะติดต่อกับ service ที่เล่นเพลง ทำให้เรามีหน้าจอไว้ควบคุมการเล่นเพลง ซึ่ง activity นี่ก็ควรจะ bindService เพื่อสร้างการติดต่อ จากนั้นจึงเรียก method ที่จะมีผลกับการเล่นเพลงต่อไป Boardcast ทำโดยการส่ง Intent object ไปยัง method เช่น Context.sendBroadcast(), Context.sendOrderedBroadcast() และ Context.sendStickyBroadcast() Android ส่ง intent ต่อให้กับ boardcast reveivers ที่สนใจด้วย method onReveiver() Shutting down components Content provider จะทำงานก็ต่อเมื่อมันตอบสนองการร้องขอของ ContentResolver และ broadcast receiver ทำงานก็ต่อเมื่อมันตอบสนองต่อ broadcast message ดังนั้นจึงไม่ต้องมีการ shutdown component พวกนี้ Activities ไม่เหมือนกัน เพราะมันมี UI มันอาจจะทำงานไปเรื่อยๆ ตราบใดที่ยังติดต่อกับ user ได้อยู่ ส่วน service อาจจะทำงานไปเรื่อยๆ ไม่มีวันหยุด ดังนั้น Android จะต้องมี method เพื่อมาปิดการทำงานของ component พวกนี้อย่างถูกต้อง - Activity สามารถ shutdown โดยเรียก method finish() Activity หนึ่งสามารถ shutdown อีก activity (ที่ start ด้วย startActivityForResult()) โดยเรียก finishActivity() - Service สามารถถูกหยุดโดย mrthod ของตุวเองชื่อ stopSelf() หรือโดยเรียก Context.stopService() Component ยังอาจจะถูกปิดโดยระบบ เมื่อมันไม่ได้ใช้งานอีกแล้ว หรือตอนที่ Android ขอ memory คืนเพื่อไปเปิด component อื่น ไปศึกษาต่อเรื่อง Component Lifecycle The manifest file ก่อนที่ Android จะสามารถ start component ของ application ของเราได้นั้น มันต้องรู้ก่อนว่ามี component นั้นอยู่ด้วย ดังนั้น application จะประกาศ component ของมันเอาไว้ใน manifest file ที่ผูกติดไปกับไฟล์ .apk ที่เก็บ code ของ application, file, resources manifest เป็น structured XML file และจะชื่อ AndroidManifest.xml เสมอ ทุกๆ application มันทำหน้าที่หลายอย่าง นอกจากประกาศ component ที่ application ใช้ เช่นบอกชื่อ libraries ที่ application ต้องการติดต่อด้วย (นอกจาก default Android library) และ บอกระดับการอนุญาติที่ application ต้องการจะได้ แต่งานหลัก ๆ ก็คือการประกาศ component ของ application นี่แหละ ตัวอย่างเช่น activity จะถูกประกาศแบบนี้ . . . ส่วน service ก็ใช้ , สำหรับ broadcast receivers, สำหรับ content provider; Activities, services, และ content provider ที่ไม่ประกาศใน manifest ระบบจะมองไม่เห็น และมันก็จะทำงานไม่ได้ อย่างไรก็ตาม broadcast reveiver สามารถประกาศใน manifest หรือสร้างขึ้นมาแบบ dynamic ใน code (เป็น BroadcastReceiver object) และ register เข้ากับ system โดยเรียก Context.registerReceiver() Intent filter Intent object สามารถประกาศชื่อ component ได้เลยตรง ๆ ถ้าเป็นอย่างนั้น Android ก็จะหา component นั้นเจอแล้วก็ activate มันได้เลย (ตามที่เซ็ตไว้ใน manifest file) แต่ถ้าเราไม่ได้ประกาศไว้อย่างชัดเจน Android จะต้องหา component ที่จะมาตอบสนอง intent อันนั้น การที่จะทำแบบนั้นได้ มันจะที่การเปรียบเทียบ intent object อันนั้น กับ intent filters ที่เป็นไปได้ filters ของ component จะบอกให้ Android รู้ถึงชนิดของ intent ที่ component สามารถจัดการได้ เช่นเดียวกันกับข้อมูลพื้นฐานอื่นๆของ component เราจะประกาศมันไว้ใน manifest file นี่คือตัวอย่างของการเพิ่ม intent filters 2 อันไปยัง activity . . . filter แรกในตัวอย่าง -- action "android.intent.action.MAIN" และ categoty "android.intent.category.LAUNCHER" -- มันจะ mark activity เป็นตัว application launcher filter ที่สองประกาศ action ที่ activity สามารถจัดการได้บน data แต่ละชนิด component นึงมีกี่ intent filter ก็ได้ filter แต่ละตัวก็ประกาศความสามารถต่างๆกัน ถ้าไม่มี filter เลย มันก็ยังสามารถถูก activate ได้จาก intents ที่ประกาศชื่อ component อย่างชัดเจนเท่านั้น สำหรับ broadcast receiver ที่ถูกสร้างขึ้นและ register ภายใน code, intent filter ถูกประกาศตรงๆเลยเป็น IntentFilter object ส่วน filter อื่นๆ จะต้องประกาศใน manifest Activities and Tasks Activity อันนึงสามารถเริ่ม activity อีกอันได้ รวมถึง activity ที่อยู่ใน application อื่น เช่นคุณอยากแสดงชื่อถนนของสถานที่หนึ่งบนแผนที่ มันมี activity ที่ทำหน้าที่อย่างนั้นอยู่แล้ว สิ่งที่คุณต้องทำก็คือ เอา Intent object กับ ข้อมูลที่จำเป็นรวมเข้าด้วยกัน แล้วผ่านมันไปยัง startActivity() ตัวแสดงแผนที่ก็จะแสดงแผนที่ จากนั้นพอ user กด back ก็กลับมาที่ activity เดิมของคุณ สำหรับ user แล้วมันเหมือนเปิดอยู่ในโปรแกรมของคุณ แต่จริงๆแล้วมันไปเปิด application อื่น แต่ run อยู่บน application ของคุณ Android ทำให้เกิดเหตุการณ์แบบนี้ได้โดยรวม 2 activity เข้าไว้ใน Task เดียวกัน, พูดให้ง่าย ๆ Task คือสิ่งที่ user เห็นว่ามันคือ 1 application ซึ่งมันจะประกอบไปด้วยกลุ่มของ activity ที่เกี่ยวข้องกัน จัดเรียงอยู่บน stack, ถ้าอันนึงเป็น running activity, activity อันก่อนหน้าก็จะถูกวางลงบน stack พอ user กด back, activity ปัจจุบันก็ถูกดึงทิ้ง แล้วอันก่อนหน้าก็จะขึ้นมาทำงานแทน Task อันนึงก็คือ stack ของ activity หลายๆอัน ไม่ใช่ class หรือ element ใดๆใน manifest file ดังนั้นจึงไม่มีทางที่เราจะ set ค่าของ task หนึ่งๆแยกจาก activity ได้ ค่าของ task หนึ่งๆ ที่มองเห็นได้ทั้งหมดอยู่ที่ root activity ทุกๆ activity ใน task ทำงานร่วมกันเหมือนเป็น unit เดียวกัน, ทั้ง task (ทั้ง activity stack) สามารถถูกดึงมาด้านหน้า หรือส่งไป background ได้ เช่น task หนึ่งมี 4 activity, 3 อันกำลังทำงาน พอ user กด home-> ไปที่ application launcher และเลือก application อื่น task เก่าก็จะไปที่ background และ root activity ของ task ใหม่ก็แสดงขึ้นมา หลังจากนั้นไม่นาน user กด back กลับไปยัง home แล้วเลือก application ที่เคยเปิดครั้งแรก, task เก่าที่มี 4 activity ค้างอยู่บน stack กลับขึ้นมาข้างหน้า พอ user กด back, หน้าจอจะไม่ได้แสดง activity ที่ user เพิ่งปิดไป (ของ task ที่สอง) แต่ กลับกัน activity บนสุดของ stack ถูกลบทิ้ง และ activity ข้างล่างใน task เดียวกันจะถูกแสดงขึ้นมาแทน สิ่งที่อธิบายไปข้างบนคือลักษณะปกติที่ activity และ task ทำงาน แต่ก็ยังมีทางที่จะแก้ไขการทำงานของมันอยู่ ความข้องเกี่ยวกันของ task และ ลักษณะการทำงานของ activity ใน task สามารถควบคุมได้โดย flag ที่ set ใน intent object ที่ start activity และ element ใน manifest จากที่กล่าวไป Intent flags คือ FLAG_ACTIVITY_NEW_TASK FLAG_ACTIVITY_CLEAR_TOP FLAG_ACTIVITY_RESET_TASK_IF_NEEDED FLAG_ACTIVITY_SINGLE_TOP ส่วน attribute คือ taskAffinity launchMode allowTaskReparenting clearTaskOnLaunch alwaysRetainTaskState finishOnTaskLaunch Affinities and new tasks โดยปกติแล้ว activity ทุกตัวใน application มีความเกี่ยวดอง (affinity) ซึ่งกันและกัน หมายความว่า มีสิทธิพิเศษภายใน task เดียวกัน อย่างไรก็ตาม ความเกี่ยวดองโดยเฉพาะก็สามารถสร้างขึ้นเองได้ สำหรับทุก activity ด้วย attribute ชื่อ taskAffinity ใน element , Activity ต่าง application สามารถแบ่งปันความเกี่ยวดองกันได้ หรือความเกี่ยวดองใน application เดียวกันสามารถใช้ได้โดย affinity อื่นได้, affinity นี้จะถูกนำมาใช้ใน 2 สถานการณ์ 1. เมื่อ intent object ที่เริ่ม activity มี FLAG_ACTIVITY_NEW_TASK flag และเมื่อ activity มี allowTaskReparenting attribute เป็น true The FLAG_ACTIVITY_NEW_TASK flag ตามที่ได้อธิบายไปว่า activity โดยปกติแล้วจะเริ่มทำงานด้วยการเรียก startActivity() มันจะถูก push ขึ้นไปบน stack เดียวกับตัวเรียก อย่างไรก็ตาม ถ้า intent object ส่ง startActivity ที่มี FLAG_ACTIVITY_NEW_TASK flag ระบบจะมองหา task ใหม่ที่จะเก็บ activity ใหม่ ส่วนใหญ่แล้วจะเป็นไปตามชื่อ flag คือมันจะเป็น task ใหม่ อย่างไรก็ตามไม่จำเป็นต้องเป็นเช่นนั้น ถ้ามันมี task ที่มี affinity เดัยวกันเปิดอยู่แล้ว activity จะเปิดบน task นั้น ถ้าไม่มีมันถึงจะเปิด task ใหม่ The allowTaskReparenting attribute ถ้า activity มี allowTaskReparenting attribute เป็น true มันสามารถเคลื่อนย้ายจาก task ที่มันเริ่ม start ไปยัง task ที่มันมี affinity เดียวกันได้เมื่อ task นั้นอยู่ข้างหน้า เช่น มี activity ที่รายงานสภาพอากาศในเมืองที่เลือกอยู่ซึ้งถูกกำหนดเป็นส่วนหนึ่งของโปรแกรมท่องเที่ยว และมันมี affinity เดียวกับอีก activity ที่อยู่บน application เดียวกัน (default affinity) และมันอนุญาติการ reparent และมี activity หนึ่งของคุณเปิด การรายงานสภาพอากาศ ที่มันเริ่มโดย task เดียวกันกับ activity ของคุณ อย่างไรก็ตามเมื่อ โปรแกรมท่องเที่ยวของคุณกลับมาอยู่ด้านหน้า การรายงานสภาพอากาศก็ถูกตั้งใหม่ให้มาอยู่ใน task นั้นแทน ถ้า .apk file หนึ่งมีหลาย application ในมุมมองของ user คุณควรจะต้อง assign affinity ให้กับ activity ตามความสัมพันธ์ของพวกมัน Launch modes เป็น attribute ของ element "standard" (the default mode) "singleTop" "singleTask" "singleInstance" 1. activity ไหนตอบสนองกับ intent
  • standard และ singleTop เป็นตัวเริ่ม intent startActivity() ส่วน singleTask และ singleInstance เป็น root ของ task เสมอและไม่สามารถเปิดได้จาก task อื่น
2. activity สามารถมีหลาย instance ได้หรือไม่
  • standard และ singleTop สามารถมีหลาย instance ได้
3. instance สามารถมี activity อื่นใน task ได้มั้ย
  • singleInstance และ singleTask เป็น activity ที่อยู่บน task เดียวเท่านั้น ถ้ามันไปเปิด activity อื่น มันจะไปเปิด task อื่น
4. instance ใหม่จะเริ่มเพื่อทำงาน intent ใหม่หรือไม่
  • standard จะมี instance ใหม่เกิดขึ้นทุก ๆ intent แต่ละ instance จัดการแค่ intent เดียว สำหรับ singleTop, instance ที่มีอยู่แล้วจะถูกใช้จัดการ intent ใหม่ถ้ามันอยู่บนสุดของ stack ถ้าไม่ก็สร้าง instance ใหม่อยู่ดี
......................... Clearing the stack ถ้า user ไม่ทำอะไรกับ task นานๆ ระบบจะ clear ทุกๆ activity ใน task ยกเว้น root activity เมื่อ user กลับมาที่ task อีกครั้ง มันก็จะกลับมาเหมือนเดิม ยกเว้นแต่ว่า activity แรกสุดเท่านั้นที่แสดงขึ้นมา มันเป็นไอเดียที่คิดว่ามันนานจน user ลืมสิ่งที่ตัวเองกำลังจะทำไปแล้ว และกพลังจะเริ่มทำอะไรใหม่แล้วล่ะ ข้างบนคือ default แต่เราสามารถควบคุม activity โดย set attribute และควบคุมมันได้ 1. alwaysRetainTaskState attribute ถ้าเป็น true ใน root activity, มันจะเก็บทุกๆ activity เอาไว้ไม่เหมือนแบบ default พอ user กลับมามันก็จะเป็นเหมือนเดิม 2. clearTaskOnLaunch ถ้าเป็น true ใน root activity, stack จะลบ activity ไปจนถึง root เมื่อไร่ก็ตามที่ user ออกจาก task ไม่ว่าจะแป๊บเดียวก็ตาม 3. finishOnTaskLaunch เหมือน clearTaskOnLaunch แต่มันทำบน activity ใด activity หนึ่ง ไม่ใช่กับทั้ง task คือมันสามารถลบ activity ใดๆก็ได้รวมถึง root ด้วย ถ้ามันเป็น true พอ user กลับมาอีกที activity นั้นจะหายไปแล้ว มีอีกวิธีที่จะลบ activity ออกจาก stack, ถ้า Intent object มี FLAG_ACTIVITY_CLEAR_TOP flag และ task เป้าหมายมี instance ของ activity ที่สามารถจัดการ intent นี้ได้อยู่ใน stack, activity ทั้งหมดที่อยู่บน instance นั้นจะถูกลบออก แล้ว instance นั้นจะขึ้นมาอยู่บนสุดของ stack และตอบสนองต่อ intent นั้นแทน ถ้า launch mode คือ "standard" มันก็จะถูกลบออกจาก stack ด้วย และ instance ใหม่จะถูกสร้างขึ้นมาทำงานกับ intent ที่เข้ามาแทน เพราะ instance ใหม่จะถูกสร้างทุกครั้งสำหรับ launch mode "standard" FLAG_ACTIVITY_CLEAR_TOP มักใช้บ่อยๆ ควบคู่กับ FLAG_ACTIVITY_NEW_TASK เมื่อใช้ร่วมกัน flag พวกนี้จะสามารถใช้เพื่อ locating activity ที่มีอยู่แล้วใน task อื่น และวางมันลงบนตำแหน่งที่มันสามารถตอบสนองต่อ intent นั้นได้ Starting tasks activity หนึ่งจะถูก set up เป็นจุดเริ่มต้นของ task โดยใส่ filter "android.intent.action.MAIN" และ category เป็น "android.intent.category.LAUNCHER", filter แบบนี้สร้าง icon และ ชื่อของ activity แสดงในการเปิด application ทำให้ user สามารถเปิดมัน และกลับมายังมันได้หลังจากเปิดไปแล้ว ความสามารถที่ user สามารถออกจาก task และกลับมาหามันได้อีกนั้นสำคัญ ดังนั้น "singleTask" และ "singleInstance" ซึ่งจะสร้าง task ใหม่จึงสามารถระบุได้แต่ใน activity ที่มี filter MAIN และ LAUNCHER เท่านั้น ถ้าไม่มี filter พวกนี้ แล้ว intent หนึ่งเกิด แล้ว user ใช้เวลากับ task นั้นสักพัก แล้ว user กด HOME แล้ว task นั้นก็ไปอยู่ด้านหลัง HOME screen แต่ user จะกลับไปไม่ได้อีกแล้ว เพราะมันไม่ได้อยู่ใน application launcher เรื่องยากอีกอย่างของ FLAG_ACTIVITY_NEW_TASK ก็คือ ถ้า flag นี้ทำให้ activity เริ่ม task ใหม่ และ user กด HOME มันจะต้องมีทางที่ user สามารถกลับมายังที่เดิมได้ บาง entity เช่น notification manager จะเริ่ม activity ใน task อื่นเสมอ และจะไม่เริ่มใน task ตัวเองเด็ดขาด มันจึงส่ง FLAG_ACTIVITY_NEW_TASK ในทุกๆ intent ที่มันส่งไปยัง startActivity() ถ้าคุณมี activity ที่เรียกใช้ entity ภายนอกและต้องการใช้ flag นี้ อย่าลืมที่จะให้ user มีวิธีที่จะกลับมายังที่ที่ task เริมทำงาน ถ้าคุณไม่อยากให้ user กลับมาได้ ให้ set ด้วย finishOnTaskLaunch เป็น true Processes and Threads Processes ....................... Threads ...................... Remote procedure calls android มี remote procedure call เรียกว่า (RPCs) ซึ่ง method จะถูกเรียกแบบ local แต่ executed แบบ remote (ในอีก process) และผลลัพธ์กลับสู่ผู้เรียกใช้ ............................. การ connect ระหว่าง client และ service - client implement onServiceConnected() และ onServiceDisconnected() method ซึ่งทำให้มีการแจ้งเตือนเมื่อสามารถเชื่อมต่อสำเร็จ และ disconnect จากนั้นมันก็เรียก bindService() เพื่อเริ่มการ connect - method onBind() ของ service จะทำงานว่าจะ accept หรือ reject connection ตาม intent ที่มันได้รับ (intent ที่ถูกส่งให้ bindService() ) ถ้า accept มันจะ return instance ของ Stub subclass - ถ้า service accept connection, Android จะเรียก method onServiceConnected() ของ client และส่ง IBinder object และ proxy สำหรับ Stub subclass คืนไปให้ client, client สามารถเรียก call บน service ได้ผ่าน proxy นั้น Thread-safe methods method ที่คุณสร้างขึ้นอาจจะถูกเรียกใช้งานได้จากหลาย thread พร้อมกัน ดังนั้นต้องเขียนขึ้นในลักษณะที่ thread-safe โดยเฉพาะ method ที่สามารถถูกเรียกแบบ remote ................................... IBinder method ถูกเรียกจากหลาย client พร้อมกัน มันจึงต้องเขียนแบบ thread-safe เช่นเดียวกับ ContentResolver และ ContentProvider method "query(), insert(), delete(), Component Lifecycles ................. Activity lifecycle ................. void onCreate(Bundle savedInstanceState) void onStart() void onRestart() void onResume() void onPause() void onStop() void onDestroy() Calling into the superclass การแก้ไข method ที่เกี่ยวกับ activity lifecycle method ควรต้องเรียก method ของ superclass ก่อน เช่น protected void onPause() { super.onPause(); . . . } ทั้ง 7 method ที่กำหนด lifecycle ทั้งหมดของ activity หนึ่งๆ มันจะมีอยู่ 3 loop ที่คุณจะต้องตรวจสอบเพื่อใช้งานมันได้ 1. entire lifetime อยู่ระหว่าง onCreate() จนถึง onDestroy(), activity จะทำการ initial setup ของ global ที่ onCreate() และ release resource ทั้งหมดที่ onDestroy() เช่น มี thread หนึ่ง ดาวน์โหลดข้อมูลจาก network, มันจะสร้าง thread นั้นที่ onCreate และหยุด thread นั้นที่ onDestroy() 2. visible lifetime เกิดขึ้นระหว่าง onStart() จนถึง onStop() ระหว่างช่วงเวลานั้น user จะเห็น activity บนจอภาพ, แม้มันอาจจะไม่ได้อยู่บนสุด หรือสามารถตอบสนองได้, ในระหว่าง 2 method นี้ คุณสามารถจัดการกับ resource ที่จำเป็นที่จะใช้แสดง activity ให้ user เห็นได้ เช่น คุณสามารถ register BroadcastReceiver ที่ onStart() เพื่อ monitor การเปลี่ยนแปลงที่กระทำต่อ UI ของคุณ และ unregister มันที่ onStop() เมื่อ user มองไม่เห็นสิ่งที่คุณแสดงอีกแล้ว onStart() และ onStop() สามารถถูกเรียกได้หลายครั้ง เปรียบได้กับ activity ต่างๆ ที่ผลัดกันระหว่าง visible กับ hidden แสดงให้ user มองเห็น 3. foreground lifetime อยู่ระหว่าง onResume() จนถึง onPause() ระหว่างเวลานี้ activity จะอยู่หน้าสุดของ activity อื่นๆ และจะตอบสนองกับ user, ปกติแล้ว activity มักจะสามารถสลับระหว่าง resumed และ paused ได้บ่อยๆ เช่น onPause() ถูกเรียกเมื่อ มือถือ sleep หรือเมื่อ activity ใหม่เริ่มทำงาน, onResume() ถูกเรียกเมื่อ ผลของ activity หรือ intent ใหม่ถูกส่งเข้ามา ดังนั้น code ใน 2 method นี้ควรจะ lightweight รูปต่อไปนี้แสดง loop และ path ของ activity, ที่เป็นรูปวงรีแสดง major state ที่ activity ทำงาน ส่วนสี่เหลี่ยมแสดง callback method ที่คุณสามารถ implement มันได้ เมื่อ activity เปลี่ยน state ตาราง method onCreate() เรียกเมื่อ activity ถูกเรียกครั้งแรก ที่นี่คุณควรทำ static set up ทั้งหมด เช่น สร้าง views, bind data to list, และอื่นๆ เราสามารถส่ง object ของ state ของ activity ก่อนหน้ามาที่ method นี้ได้ onRestart() เรียกเมื่อ activity ถูกหยุดไปครั้งก่อน จากนั้นถูกเปิดอีกครั้ง onStart() ถูกเรียกเมื่อ activity ขึ้นมาให้ user ได้เห็น ไปต่อ onResume() เมื่อ activity ขึ้นมาอยู่หน้าสุด หรือ onStop() ถ้ามัน hidden onResume() ถูกเรียกก่อนที่ activity จะเริ่มตอบสนองกับ user, ณ จุดนี้ activity จะอยู่บนสุดของ stack และรับ user input ไปต่อ onPause() onPause() ถูกเรียกเมื่อระบบจะ resume activity อื่น, ปกติแล้ว method นี้จะถูกใช้เพื่อ commit การเปลี่ยนแปลงที่ไม่ได้ save ไว้เพื่อ persistent ข้อมูล, หยุด animations และสิ่งอื่นๆ ที่จะกิน CPU และ resource, และมันควรทำทุกอย่างด้วยความรวดเร็ว เพราะ activity อื่นจะไม่เปิดขึ้นมาจนกระทั่ง method นี้ return ไปต่อ onResume() ถ้ากลับมาข้างหน้า หรือ onStop() ถ้า user มองไม่เห็นอีกแล้ว onStop() ถูกเรียกเมื่อ activity ไม่สามารถมองเห็นได้โดย user อีก อาจจะเพราะกำลังถูก destroy หรือเพราะ activity อื่น (ไม่ว่ามีอยู่แล้วหรือสร้างใหม่) ถูกเปิดขึ้นมาแล้วกำลังจะ cover มันหมด ไปต่อ onRestart() ถ้ามันกลับมาตอบสนองกับ user หรือ onDestroy() เมื่อ activity จะจบลง onDestroy() ถูกเรียกก่อนที่ activity จะถูกทำลาย นี่เป็นการเรียกครั้งสุดท้ายที่ activity จะได้รับ อาจจะเพราะ activity เสร็จสิ้น (มีการเรียก finish() บนมัน) หรือเพราะระบบต้องการ destroy instance ของ activity นี้ชั่วคราวเพื่อต้องการพื้นที่ คุณสามารถแยกระหว่างการปิด 2 แบบนี้ได้ด้วย isFinishing() Note! Killable - No, No, No, No, Yes, Yes, Yes Killable บอกว่าระบบสามารถ kill process ที่ host activity "ได้ตลอดเวลาหลังจาก method return, โดยไม่ต้อง execute code อื่นๆของ activity อีก", onPause(), onStop(), onDestroy() ถูก mark ว่า Yes เพราะ onPause() เป็น method แรกที่สามารถการันตีว่าจะถูกเรียกก่อนที่ process จะถูก kill, และคุณสามารถ write ข้อมูลที่ persistent (เช่น user edit) ลงบนหน่วยความจำได้ทัน ซึ่ง onStop() และ onDestoy() ก็เช่นเดียวกัน แต่ 2 อันหลังไม่สามารถการันตีได้ คุณจึงควร save งานที่ onPause() No ที่ Killable ป้องกัน process จากการที่ activity ถูก kill ในระหว่างที่กำลังถูกเรียก หรือระหว่างกำลังทำงาน ดังนั้น activity ที่ตอนแรกอยู่ที่ onPause() แล้วถูกเรียก onResume() จะไม่สามารถถูก kill ได้จนกว่าจะถึง onPause() อีกครั้ง แต่อย่างไรก็ตาม activity ที่ไม่สามารถถูก kill ได้ในทางเทคนิค ก็ยังสามารถ kill ได้โดยระบบ แต่จะเกิดในกรณีเฉพาะจริงๆ และเหตุการณ์ที่ไม่มี resource อื่นให้ใช้งานอีกแล้วเท่านั้น Saving activity state เมื่อระบบ shut down activity อัตโนมัติเพื่อขอ memory โดยไม่ได้มาจากความต้องการของ user, user ก็จะต้องสามารถกลับไปยัง activity ก่อนหน้าได้ เพื่อจับ state ก่อนหน้าก่อนที่ activity จะโดน kill คุณสามารถ implement method ชื่อ onSaveInstanceState() เพื่อ activity นั้นได้, Android จะเรียก method นี้ก่อนที่จะทำให้ activity สามารถ destroy ได้ นั่นคือ ก่อนที่ onPause() จะถูกเรียก มันจะส่ง Bundle object ที่คุณสามารถบันทึก dynamic state ของ activity เป็นแบบคู่ของ name-value ไว้ได้ เมื่อ activity จะเริ่มทำงานอีกครั้ง Bundle นี้จะถูกส่งมาที่ onCreate() และ method ที่ถูกเรียก หลัง onStart(), onRestoreInstanceState() ดังนั้น method อันใดอันนึงหรือทั้งคู่สามารถกลับไปสร้าง state เดิมได้ ต่างจาก onPause() และ method อื่นๆข้างบน, onSaveInstanceState() และ onRestoreInstanceState() ไม่ใช่ lifecycle method มันไม่ได้ถูกเรียกทุกครั้ง เช่น Android จะเรียก onSaveInstanceState() ก่อนที่ activity จะสามารถถูก destroy โดยระบบได้ แต่จะไม่เรียกเมื่อ จะถูก destroy โดยการกระทำของ user เช่น กด BACK ในกรณีนี้ user ไม่ต้องการกลับไป activity นั้นอีกจึงไม่มีเหตุผลที่ต้อง save state เพราะ onSaveInstanceState() ไม่ได้ถูกเรียกทุกครั้ง, คุณควรใช้มันเพื่อการบันทึก state ชั่วคราวไม่ใช่ บันทึก persistent data, แต่ให้ใช้ onPause() แทนเพื่อการนั้น Coordinating activities เมื่อ activity หนึ่งเรียกอีก activity หนึ่งมันทั้งคู่จะเจอการเปลี่ยน lifecycle, อันนึง pause และอาจจะ stop อีกอัน start ในกรณีนี้คุณอาจจำเป็นจะต้อง ให้มันประสานงานกันจากอันนึงไปอีกอันนึง ลำดับของ lifecycle callback ถูกกำหนดไว้อย่างดี โดยเฉพาะเมื่อทั้งสอง activity อยู่บน process เดียวกัน 1. activity แรกเรียก onPause() 2. activity สองเรียก onCreate(), onStart() และ onResume() 3. เมื่อ activity สองไม่สามารถมองเห็นได้จากจอแล้วจะถูกเรียก onStop() Service lifecycle service สามารถถูกใช้ได้ 2 ทาง 1. start และทำงานจนกระทั่งมีคนไป stop หรือมันหยุดตัวเอง ถ้าแบบนี้มันจะเริ่มด้วย Context.startService() และหยุดด้วย Context.stopService() หรือหยุดตัวเองโดย Service.stopSelf() หรือ Service.stopSelfResult, แค่ stopService() อันนเดียวก็พอที่จะถูกเรียกในการหยุด service หนึ่งๆ ไม่ว่าจะถูกเรียก startService() กี่ครั้ง 2. ทำงานแบบสามารถโปรแกรมได้โดยใช้ interface ที่มัน define และ export, Clients จะสร้าง connection ไปยัง object ของ Service object และใช้ connection นั้นเรียกไปยัง service การสร้าง connection โดยเรียก Context.bindService() และปิดโดย Context.unbindService() หลาย client สามารถ bind ไปยัง service เดียวกัน ถ้า service ยังไม่ทำงาน bindService() สามารถสั่งให้มันทำงานได้ 2 mode นี้ไม่ได้แยกจากกันโดยสิ้นเชิง คุณสามารถ bind service ที่เริ่มโดย startService() ได้ เช่น เล่นเพลงด้วยการเรียก startService() ด้วย intent object ที่บอกให้เล่นเพลง แล้วซักพัก user อยากควบคุม หรือรู้รายละเอียดของเพลง ก็จะมี activity มาสร้าง connection กับ service ด้วย bindService() ในกรณีนี้ stopService() จะไม่สามารถหยุด service ได้จริงๆ จนกว่าการ bind ครั้งสุดท้ายจะ close เช่นเดียวกับ activity, service ก็มี lifecycle แต่มีแค่ 3 อัน void onCreate() void onStart(Intent intent) void onDestroy() มี 2 loop ที่จะ implement service ได้ 1. entire lifetime อยู่ในระหว่าง onCreate() และ return ของ onDestroy() เช่นเดียวกับ activity มันจะทำ set up ครั้งแรกที่ onCreate() และปล่อย resource ทั้งหมดที่ onDestroy() ตัวอย่างเช่น service ที่ใช้เล่นเพลง จะสร้าง thread ไว้เล่นเพลงที่ onCreate() 2. active lifetime อยู่หลัง onStart()

ไม่มีความคิดเห็น:

แสดงความคิดเห็น

Search