UI ของเฟรมเวิร์กแอป Android อิงตามลําดับชั้นของออบเจ็กต์ที่เริ่มต้นด้วย View องค์ประกอบ UI ทั้งหมดต้องผ่านชุดการวัดและกระบวนการจัดวางที่ปรับให้พอดีกับพื้นที่สี่เหลี่ยมผืนผ้า จากนั้นระบบจะแสดงผลออบเจ็กต์มุมมองที่มองเห็นทั้งหมดไปยังแพลตฟอร์มที่ WindowManager ตั้งค่าไว้เมื่อนําแอปมาไว้ที่เบื้องหน้า ด้าย UI ของแอปจะจัดวางและแสดงผลไปยังบัฟเฟอร์ต่อเฟรม
SurfaceView
SurfaceView คือคอมโพเนนต์ที่คุณสามารถใช้เพื่อฝังเลเยอร์คอมโพสิตเพิ่มเติมภายในลําดับชั้นของมุมมอง SurfaceView จะใช้พารามิเตอร์เลย์เอาต์เดียวกับมุมมองอื่นๆ จึงสามารถจัดการได้เหมือนมุมมองอื่นๆ แต่เนื้อหาของ SurfaceView จะเป็นแบบโปร่งใส
เมื่อแสดงผลด้วยแหล่งที่มาของบัฟเฟอร์ภายนอก เช่น บริบท GL หรือโปรแกรมถอดรหัสสื่อ คุณจะต้องคัดลอกบัฟเฟอร์จากแหล่งที่มาของบัฟเฟอร์เพื่อแสดงบัฟเฟอร์บนหน้าจอ การใช้ SurfaceView ช่วยให้คุณทำสิ่งนั้นได้
เมื่อคอมโพเนนต์มุมมองของ SurfaceView กำลังจะปรากฏขึ้น เฟรมเวิร์กจะขอให้ SurfaceControl ขอพื้นผิวใหม่จาก SurfaceFlinger หากต้องการรับการเรียกกลับเมื่อสร้างหรือทำลายพื้นผิว ให้ใช้อินเทอร์เฟซ SurfaceHolder โดยค่าเริ่มต้น ระบบจะวางแพลตฟอร์มที่สร้างขึ้นใหม่ไว้ด้านหลังแพลตฟอร์ม UI ของแอป คุณสามารถลบล้างการจัดเรียงตามลําดับ Z เริ่มต้นเพื่อวางพื้นผิวใหม่ไว้ที่ด้านบนได้
การแสดงผลด้วย SurfaceView มีประโยชน์ในกรณีที่คุณต้องแสดงผลไปยังพื้นผิวแยกต่างหาก เช่น เมื่อแสดงผลด้วย Camera API หรือบริบท OpenGL ES เมื่อคุณแสดงผลด้วย SurfaceView ทาง SurfaceFlinger จะคอมโพสบัฟเฟอร์ไปยังหน้าจอโดยตรง หากไม่มี SurfaceView คุณจะต้องคอมโพสิทบบัฟเฟอร์ไปยังพื้นผิวนอกหน้าจอ จากนั้นจึงคอมโพสิทไปยังหน้าจอ ดังนั้นการแสดงผลด้วย SurfaceView จึงช่วยลดงานที่ไม่จำเป็น หลังจากแสดงผลด้วย SurfaceView แล้ว ให้ใช้เธรด UI เพื่อประสานงานกับวงจรชีวิตของกิจกรรม และปรับขนาดหรือตําแหน่งของมุมมองหากจําเป็น จากนั้นเครื่องมือประกอบฮาร์ดแวร์จะผสาน UI ของแอปเข้ากับเลเยอร์อื่นๆ
พื้นผิวใหม่คือฝั่งผู้ผลิตของ BufferQueue ซึ่งผู้บริโภคคือเลเยอร์ SurfaceFlinger คุณสามารถอัปเดตพื้นผิวด้วยกลไกใดก็ได้ที่ส่งข้อมูลไปยัง BufferQueue เช่น ฟังก์ชัน Canvas ที่พื้นผิวระบุ การแนบ EGLSurface และการวาดบนพื้นผิวด้วย GLES หรือการกำหนดค่าโปรแกรมถอดรหัสสื่อเพื่อเขียนพื้นผิว
SurfaceView และวงจรของกิจกรรม
เมื่อใช้ SurfaceView ให้แสดงผลพื้นผิวจากเธรดอื่นที่ไม่ใช่เธรด UI หลัก
สําหรับกิจกรรมที่มี SurfaceView จะมีสถานะแมชชีน 2 รายการที่แยกกันแต่มีความสัมพันธ์กัน ดังนี้
- แอป
onCreate
/onResume
/onPause
- พื้นผิวที่สร้าง/เปลี่ยนแปลง/ลบ
เมื่อกิจกรรมเริ่มต้นขึ้น คุณจะได้รับ Callback ตามลําดับนี้
onCreate()
onResume()
surfaceCreated()
surfaceChanged()
หากคลิกกลับ คุณจะได้รับสิ่งต่อไปนี้
onPause()
surfaceDestroyed()
(เรียกใช้ก่อนที่พื้นผิวจะหายไป)
หากคุณหมุนหน้าจอ กิจกรรมจะถูกยกเลิกและสร้างใหม่เพื่อให้คุณเห็นวงจรทั้งหมด คุณดูได้ว่าเป็นการรีสตาร์ทอย่างรวดเร็วโดยดูที่ isFinishing()
เป็นไปได้ที่กิจกรรมจะเริ่มต้น/หยุดลงอย่างรวดเร็วจน surfaceCreated()
เกิดขึ้นหลังจาก onPause()
หากแตะปุ่มเปิด/ปิดเพื่อปิดหน้าจอ คุณจะเห็นแค่ onPause()
ที่ไม่มี surfaceDestroyed()
พื้นผิวจะยังคงทำงานอยู่และแสดงผลต่อไปได้ คุณจะได้รับเหตุการณ์ของผู้ออกแบบท่าเต้นต่อไปได้หากยังคงขอ หากคุณมีหน้าจอล็อกที่บังคับให้ใช้การวางแนวอื่น กิจกรรมอาจเริ่มต้นอีกครั้งเมื่ออุปกรณ์เลิกแสดงหน้าจอว่าง หรือจะออกจากหน้าจอว่างด้วยพื้นผิวเดิมก็ได้
อายุการใช้งานของเธรดจะเชื่อมโยงกับแพลตฟอร์มหรือกิจกรรม ทั้งนี้ขึ้นอยู่กับสิ่งที่คุณต้องการให้เกิดขึ้นเมื่อหน้าจอว่างเปล่า ด้ายสามารถเริ่ม/หยุดเมื่อกิจกรรมเริ่ม/หยุด หรือเมื่อสร้าง/ทำลายพื้นผิว
การมี Thread start/stop ใน Activity start/stop ทำงานร่วมกับวงจรชีวิตของแอปได้ดี คุณเริ่มเธรดโปรแกรมแสดงผลใน onResume()
และหยุดใน onStop()
เมื่อสร้างและกำหนดค่าชุดข้อความ บางครั้งแพลตฟอร์มก็มีอยู่แล้ว และบางครั้งก็ไม่มี (เช่น แพลตฟอร์มยังคงทำงานอยู่หลังจากสลับหน้าจอด้วยปุ่มเปิด/ปิด) คุณต้องรอให้ระบบสร้างแพลตฟอร์มขึ้นมาก่อนจึงจะเริ่มต้นใช้งานในชุดข้อความได้ คุณไม่สามารถเริ่มต้นค่าในsurfaceCreate()
callback ได้ เนื่องจากจะไม่ทํางานอีกครั้งหากไม่ได้สร้างแพลตฟอร์มขึ้นมาใหม่ แต่ให้ค้นหาหรือแคชสถานะของพื้นผิว แล้วส่งต่อไปยังเธรดโปรแกรมแสดงผลแทน
การเริ่มต้น/หยุดเทรดเมื่อสร้าง/ทำลายพื้นผิวจะทำงานได้ดีเนื่องจากพื้นผิวและโปรแกรมแสดงผลมีความเชื่อมโยงกันตามตรรกะ คุณเริ่มชุดข้อความหลังจากที่สร้างพื้นผิวแล้ว ซึ่งจะช่วยหลีกเลี่ยงข้อกังวลบางอย่างในการสื่อสารระหว่างชุดข้อความ และระบบจะส่งต่อข้อความที่สร้างขึ้น/เปลี่ยนแปลงในพื้นผิว หากต้องการให้การแสดงผลหยุดเมื่อหน้าจอเป็นสีขาวและกลับมาทำงานต่อเมื่อหน้าจอกลับมาแสดงผลอีกครั้ง ให้บอก Choreographer ให้หยุดเรียกใช้การเรียกกลับการวาดเฟรม onResume()
ดำเนินการ Callback ต่อหากเธรดโปรแกรมแสดงผลทำงานอยู่ อย่างไรก็ตาม หากคุณแสดงภาพเคลื่อนไหวตามเวลาที่ผ่านไประหว่างเฟรม ก็อาจเกิดช่องว่างขนาดใหญ่ก่อนที่เหตุการณ์ถัดไปจะมาถึง การใช้ข้อความหยุดชั่วคราว/เล่นต่ออย่างชัดเจนจะช่วยแก้ปัญหานี้ได้
ตัวเลือกทั้ง 2 รายการนี้ (ไม่ว่าอายุการใช้งานของเธรดจะเชื่อมโยงกับกิจกรรมหรือแพลตฟอร์ม) จะมุ่งเน้นที่วิธีกำหนดค่าเธรดโปรแกรมแสดงผลและดูว่าเธรดดังกล่าวกำลังทำงานอยู่หรือไม่ ข้อกังวลที่เกี่ยวข้องคือการดึงข้อมูลสถานะจากเธรดเมื่อมีการหยุดกิจกรรม (ใน onStop()
หรือ onSaveInstanceState()
) ในกรณีเช่นนี้ การเชื่อมโยงอายุของเธรดกับกิจกรรมจะมีประสิทธิภาพดีที่สุด เนื่องจากหลังจากเข้าร่วมเธรดโปรแกรมแสดงผลแล้ว คุณจะเข้าถึงสถานะเธรดที่ได้รับการแสดงผลได้โดยไม่ต้องใช้พรอมต์การซิงค์
GLSurfaceView
คลาส GLSurfaceView มีคลาสตัวช่วยสำหรับจัดการบริบท EGL, การสื่อสารระหว่างเธรด และการโต้ตอบกับวงจรชีวิตของกิจกรรม คุณไม่จำเป็นต้องใช้ GLSurfaceView เพื่อใช้ GLES
ตัวอย่างเช่น GLSurfaceView จะสร้างเธรดสำหรับการแสดงผลและกำหนดค่าบริบท EGL ไว้ที่นั่น ระบบจะล้างสถานะโดยอัตโนมัติเมื่อกิจกรรมหยุดชั่วคราว แอปส่วนใหญ่ไม่จำเป็นต้องทราบข้อมูลใดๆ เกี่ยวกับ EGL เพื่อใช้ GLES กับ GLSurfaceView
ในกรณีส่วนใหญ่ GLSurfaceView จะช่วยให้ใช้งาน GLES ได้ง่ายขึ้น ในบางสถานการณ์ ข้อความอาจรบกวน