แนวคิดและการใช้งาน Jetpack Compose
ตั้งแต่ Android 3.0 (ระดับ API 11) เป็นต้นไป ไปป์ไลน์การแสดงผล 2 มิติของ Android รองรับการเร่งฮาร์ดแวร์ ซึ่งหมายความว่าการวาดทั้งหมดที่ดำเนินการบน Canvas ของ View จะใช้ GPU
เนื่องจากต้องใช้ทรัพยากรมากขึ้นในการเปิดใช้การเร่งด้วยฮาร์ดแวร์
แอปของคุณจึงใช้ RAM มากขึ้น
การเร่งฮาร์ดแวร์จะเปิดใช้โดยค่าเริ่มต้นหากระดับ API เป้าหมายเป็น
>=14 แต่ก็เปิดใช้โดยชัดแจ้งได้เช่นกัน หากแอปพลิเคชันใช้เฉพาะ
มุมมองมาตรฐานและ Drawable การเปิดใช้ทั่วโลกไม่ควรทำให้เกิด
เอฟเฟกต์การวาดที่ไม่พึงประสงค์ อย่างไรก็ตาม เนื่องจากระบบไม่รองรับการเร่งด้วยฮาร์ดแวร์สำหรับการดำเนินการวาดภาพ 2 มิติทั้งหมด การเปิดใช้จึงอาจส่งผลต่อมุมมองที่กำหนดเองหรือการเรียกวาดภาพบางรายการ โดยปกติแล้วปัญหาจะแสดงในรูปแบบของ
องค์ประกอบที่มองไม่เห็น ข้อยกเว้น หรือพิกเซลที่แสดงผลอย่างไม่ถูกต้อง Android จึงมีตัวเลือกให้คุณเปิดหรือปิดใช้การเร่งฮาร์ดแวร์ในหลายระดับเพื่อแก้ไขปัญหานี้
ดูควบคุมการเร่งฮาร์ดแวร์
หากแอปพลิเคชันของคุณทำการวาดที่กำหนดเอง ให้ทดสอบแอปพลิเคชันในอุปกรณ์ฮาร์ดแวร์จริงโดยเปิดใช้การเร่งฮาร์ดแวร์เพื่อค้นหาปัญหา ส่วนการรองรับการดำเนินการวาดภาพจะอธิบายปัญหาที่ทราบเกี่ยวกับฮาร์ดแวร์ เร่งความเร็วและวิธีแก้ไขปัญหา
ดูOpenGL ด้วย Framework API และ Renderscript ด้วย
ควบคุมการเร่งฮาร์ดแวร์
คุณควบคุมการเร่งฮาร์ดแวร์ได้ในระดับต่อไปนี้
- แอปพลิเคชัน
- กิจกรรม
- หน้าต่าง
- ดู
ระดับแอปพลิเคชัน
ในไฟล์ Manifest ของ Android ให้เพิ่มแอตทริบิวต์ต่อไปนี้ลงในแท็ก
<application> เพื่อเปิดใช้การเร่งด้วยฮาร์ดแวร์สำหรับทั้งแอปพลิเคชัน
<application android:hardwareAccelerated="true" ...>
ระดับกิจกรรม
หากแอปพลิเคชันทำงานไม่ถูกต้องเมื่อเปิดการเร่งด้วยฮาร์ดแวร์
ทั่วโลก คุณสามารถควบคุมการเร่งด้วยฮาร์ดแวร์สำหรับกิจกรรมแต่ละอย่างได้เช่นกัน หากต้องการเปิดหรือปิดใช้การเร่งฮาร์ดแวร์ที่ระดับกิจกรรม คุณสามารถใช้แอตทริบิวต์ android:hardwareAccelerated สำหรับองค์ประกอบ <activity>
ตัวอย่างต่อไปนี้จะเปิดใช้การเร่งฮาร์ดแวร์สำหรับทั้งแอปพลิเคชัน แต่
ปิดใช้สำหรับกิจกรรมหนึ่ง
<application android:hardwareAccelerated="true">
<activity ... />
<activity android:hardwareAccelerated="false" />
</application>
ระดับหน้าต่าง
หากต้องการควบคุมที่ละเอียดยิ่งขึ้น คุณสามารถเปิดใช้การเร่งด้วยฮาร์ดแวร์ สำหรับหน้าต่างที่ต้องการได้ด้วยโค้ดต่อไปนี้
Kotlin
window.setFlags( WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED )
Java
getWindow().setFlags( WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
ระดับข้อมูลพร็อพเพอร์ตี้
คุณปิดใช้การเร่งด้วยฮาร์ดแวร์สำหรับมุมมองแต่ละรายการได้ในขณะรันไทม์ด้วยโค้ดต่อไปนี้
Kotlin
myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null)
Java
myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
ตรวจสอบว่ามุมมองมีการเร่งด้วยฮาร์ดแวร์หรือไม่
บางครั้งแอปพลิเคชันอาจต้องทราบว่าขณะนี้มีการเร่งด้วยฮาร์ดแวร์หรือไม่ โดยเฉพาะอย่างยิ่งสำหรับสิ่งต่างๆ เช่น มุมมองที่กำหนดเอง วิธีนี้มีประโยชน์อย่างยิ่งหากแอปพลิเคชันของคุณวาดภาพที่กำหนดเองเป็นจำนวนมาก และไปป์ไลน์การแสดงผลใหม่ไม่รองรับการดำเนินการทั้งหมดอย่างถูกต้อง
คุณตรวจสอบว่าแอปพลิเคชันเร่งด้วยฮาร์ดแวร์หรือไม่ได้ 2 วิธีดังนี้
View.isHardwareAcceleratedจะแสดงtrueหากViewเชื่อมต่อกับหน้าต่างที่เร่งด้วยฮาร์ดแวร์Canvas.isHardwareAcceleratedจะแสดงผลtrueหากCanvasมีการเร่งด้วยฮาร์ดแวร์
หากต้องทำการตรวจสอบนี้ในโค้ดการวาด ให้ใช้
Canvas.isHardwareAccelerated แทน
View.isHardwareAccelerated เมื่อเป็นไปได้ เมื่อแนบ View กับหน้าต่างที่เร่งด้วยฮาร์ดแวร์ คุณจะยังวาดโดยใช้ Canvas ที่ไม่เร่งด้วยฮาร์ดแวร์ได้ ซึ่งเกิดขึ้นได้ เช่น เมื่อวาดมุมมองลงในบิตแมปเพื่อวัตถุประสงค์ในการแคช
โมเดลการวาดภาพของ Android
เมื่อเปิดใช้การเร่งฮาร์ดแวร์ เฟรมเวิร์ก Android จะใช้โมเดลการวาดภาพใหม่ที่ใช้รายการที่แสดงเพื่อแสดงผลแอปพลิเคชันบนหน้าจอ หากต้องการทำความเข้าใจรายการที่แสดงและวิธีที่รายการดังกล่าวอาจส่งผลต่อแอปพลิเคชันของคุณอย่างเต็มที่ คุณควรทำความเข้าใจวิธีที่ Android วาดมุมมองโดยไม่มีการเร่งด้วยฮาร์ดแวร์ด้วย ส่วนต่อไปนี้จะอธิบายโมเดลการวาดภาพที่ใช้ซอฟต์แวร์และ ฮาร์ดแวร์เร่งความเร็ว
โมเดลการวาดภาพที่อิงตามซอฟต์แวร์
ในโมเดลการวาดซอฟต์แวร์ มุมมองจะวาดด้วย 2 ขั้นตอนต่อไปนี้
- ทำให้ลำดับชั้นไม่ถูกต้อง
- วาดลำดับชั้น
เมื่อใดก็ตามที่แอปพลิเคชันต้องอัปเดตส่วนหนึ่งของ UI แอปพลิเคชันจะเรียกใช้
invalidate() (หรือตัวแปรอย่างใดอย่างหนึ่ง) ในมุมมองใดก็ตามที่มีการเปลี่ยนแปลง
เนื้อหา ข้อความการลบล้างจะเผยแพร่ไปจนถึงลำดับชั้นการแสดงผลเพื่อคำนวณภูมิภาคของหน้าจอที่ต้องวาดใหม่ (ภูมิภาคที่มีการแก้ไข) จากนั้นระบบ Android จะวาดมุมมองใดๆ ในลำดับชั้นที่
ตัดกับรีเจียนที่ต้องอัปเดต อย่างไรก็ตาม โมเดลการวาดภาพนี้มีข้อเสีย 2 ประการ
ดังนี้
ประการแรก โมเดลนี้ต้องมีการเรียกใช้โค้ดจำนวนมากในทุกๆ การส่งผ่านการวาด ตัวอย่างเช่น หากแอปพลิเคชันเรียกใช้
invalidateในปุ่มและปุ่มนั้นอยู่ด้านบนของอีกมุมมองหนึ่ง ระบบ Android จะวาดมุมมองใหม่แม้ว่าจะไม่มีการเปลี่ยนแปลงก็ตามปัญหาที่ 2 คือโมเดลการวาดอาจซ่อนข้อบกพร่องในแอปพลิเคชันของคุณ เนื่องจากระบบ Android จะวาดมุมมองใหม่เมื่อมุมมองตัดกับพื้นที่ที่ต้องวาดใหม่ มุมมองที่มีเนื้อหาที่คุณเปลี่ยนแปลงอาจถูกวาดใหม่แม้ว่าจะไม่ได้เรียกใช้
invalidateในมุมมองนั้นก็ตาม เมื่อเกิดกรณีเช่นนี้ คุณจะต้องอาศัย การลบล้างมุมมองอื่นเพื่อให้ได้ลักษณะการทำงานที่เหมาะสม ลักษณะการทำงานนี้ อาจเปลี่ยนแปลงทุกครั้งที่คุณแก้ไขแอปพลิเคชัน ด้วยเหตุนี้ คุณจึงควรเรียกใช้invalidateในมุมมองที่กำหนดเองทุกครั้งที่แก้ไขข้อมูล หรือสถานะที่ส่งผลต่อโค้ดการวาดของมุมมอง
โมเดลการวาดภาพที่มีการเร่งด้วยฮาร์ดแวร์
ระบบ Android ยังคงใช้ invalidate และ draw เพื่อขอ
อัปเดตหน้าจอและแสดงผลวิว แต่จะจัดการการวาดจริงแตกต่างกัน
ระบบ Android จะบันทึกคำสั่งการวาดไว้ในรายการที่แสดง ซึ่งมีเอาต์พุตของโค้ดการวาดของลำดับชั้นของ View แทนที่จะเรียกใช้คำสั่งการวาดทันที
การเพิ่มประสิทธิภาพอีกอย่างคือระบบ Android จะต้องบันทึกและอัปเดตรายการแสดงผลสำหรับมุมมองที่ทำเครื่องหมายว่ามีการแก้ไขโดยการเรียก invalidate เท่านั้น มุมมองที่ยังไม่ถือว่าไม่ถูกต้องสามารถวาดใหม่ได้
โดยการออกรายการที่แสดงที่บันทึกไว้ก่อนหน้านี้อีกครั้ง โมเดลการวาดภาพใหม่
มี 3 ขั้นตอนดังนี้
ทำให้ลำดับชั้นไม่ถูกต้อง
บันทึกและอัปเดตรายการที่แสดง
วาดรายการที่แสดง
โมเดลนี้ทำให้คุณไม่สามารถพึ่งพามุมมองที่ตัดกับพื้นที่ที่เปลี่ยนแปลงเพื่อเรียกใช้เมธอด draw ได้ หากต้องการให้ระบบ Android บันทึกรายการแสดงผลของ View คุณต้องเรียกใช้ invalidate การลืมทำเช่นนี้
จะทำให้มุมมองดูเหมือนเดิมแม้ว่าจะมีการเปลี่ยนแปลงแล้วก็ตาม
การใช้รายการแสดงยังช่วยเพิ่มประสิทธิภาพของภาพเคลื่อนไหวด้วย เนื่องจากเมื่อตั้งค่าพร็อพเพอร์ตี้ที่เฉพาะเจาะจง เช่น อัลฟ่าหรือการหมุน คุณไม่จำเป็นต้องทำให้มุมมองเป้าหมายไม่ถูกต้อง (ระบบจะดำเนินการโดยอัตโนมัติ) การเพิ่มประสิทธิภาพนี้จะมีผลกับ
มุมมองที่มีรายการแสดงผลด้วย (มุมมองใดก็ได้เมื่อแอปพลิเคชันของคุณเป็นฮาร์ดแวร์
เร่งความเร็ว) เช่น สมมติว่ามี LinearLayout ที่มี
ListView อยู่เหนือ Button รายการที่แสดงสำหรับ
LinearLayout มีลักษณะดังนี้
DrawDisplayList(ListView)DrawDisplayList(Button)
สมมติว่าตอนนี้คุณต้องการเปลี่ยนความทึบของ ListView หลังจากเรียกใช้ setAlpha(0.5f) ใน ListView แล้ว ตอนนี้รายการที่แสดงจะมีข้อมูลต่อไปนี้
SaveLayerAlpha(0.5)DrawDisplayList(ListView)RestoreDrawDisplayList(Button)
ไม่ได้เรียกใช้โค้ดการวาดที่ซับซ้อนของ ListView แต่ระบบ
จะอัปเดตเฉพาะรายการที่แสดงของ LinearLayout ที่ง่ายกว่ามาก
ในแอปพลิเคชันที่ไม่ได้เปิดใช้การเร่งด้วยฮาร์ดแวร์ ระบบจะเรียกใช้โค้ดการวาดของทั้งลิสต์และองค์ประกอบหลักอีกครั้ง
การรองรับการดำเนินการวาด
เมื่อเร่งด้วยฮาร์ดแวร์ ไปป์ไลน์การแสดงผล 2 มิติจะรองรับการดำเนินการวาดภาพ Canvas ที่ใช้กันมากที่สุด รวมถึงการดำเนินการอื่นๆ ที่ใช้กันน้อยกว่า ระบบรองรับการดำเนินการวาดภาพทั้งหมดที่ใช้ในการแสดงผลแอปพลิเคชันที่มาพร้อมกับ Android, วิดเจ็ตและเลย์เอาต์เริ่มต้น รวมถึงเอฟเฟกต์ภาพขั้นสูงทั่วไป เช่น การสะท้อนและพื้นผิวแบบเรียงต่อกัน
ตารางต่อไปนี้อธิบายระดับการสนับสนุนของการดำเนินการต่างๆ ในระดับ API
| ระดับ API ที่รองรับเป็นครั้งแรก | ||||
| Canvas | ||||
| drawBitmapMesh() (อาร์เรย์สี) | 18 | |||
| drawPicture() | 23 | |||
| drawPosText() | 16 | |||
| drawTextOnPath() | 16 | |||
| drawVertices() | 29 | |||
| setDrawFilter() | 16 | |||
| clipPath() | 18 | |||
| clipRegion() | 18 | |||
| clipRect(Region.Op.XOR) | 18 | |||
| clipRect(Region.Op.Difference) | 18 | |||
| clipRect(Region.Op.ReverseDifference) | 18 | |||
| clipRect() พร้อมการหมุน/มุมมอง | 18 | |||
| สี | ||||
| setAntiAlias() (สำหรับข้อความ) | 18 | |||
| setAntiAlias() (สำหรับเส้น) | 16 | |||
| setFilterBitmap() | 17 | |||
| setLinearText() | ✗ | |||
| setMaskFilter() | ✗ | |||
| setPathEffect() (สำหรับเส้น) | 28 | |||
| setShadowLayer() (นอกเหนือจากข้อความ) | 28 | |||
| setStrokeCap() (สำหรับเส้น) | 18 | |||
| setStrokeCap() (สำหรับจุด) | 19 | |||
| setSubpixelText() | 28 | |||
| Xfermode | ||||
| PorterDuff.Mode.DARKEN (framebuffer) | 28 | |||
| PorterDuff.Mode.LIGHTEN (เฟรมบัฟเฟอร์) | 28 | |||
| PorterDuff.Mode.OVERLAY (เฟรมบัฟเฟอร์) | 28 | |||
| Shader | ||||
| ComposeShader ภายใน ComposeShader | 28 | |||
| เชดเดอร์ประเภทเดียวกันภายใน ComposeShader | 28 | |||
| เมทริกซ์ในเครื่องบน ComposeShader | 18 | |||
การปรับขนาด Canvas
เราสร้างไปป์ไลน์การแสดงผล 2 มิติที่เร่งด้วยฮาร์ดแวร์ขึ้นมาเป็นอันดับแรกเพื่อรองรับ การวาดที่ไม่ปรับขนาด โดยการดำเนินการวาดบางอย่างจะลดคุณภาพลงอย่างมาก เมื่อค่าการปรับขนาดสูงขึ้น การดำเนินการเหล่านี้จะใช้เป็นพื้นผิวที่วาดที่ สเกล 1.0 ซึ่ง GPU จะแปลง ตั้งแต่ระดับ API 28 เป็นต้นไป การวาดทั้งหมดจะปรับขนาดได้โดยไม่มีปัญหา
ตารางต่อไปนี้แสดงเวลาที่มีการเปลี่ยนแปลงการติดตั้งใช้งานเพื่อให้จัดการ ขนาดใหญ่ได้อย่างถูกต้อง
| การดำเนินการวาดที่จะปรับขนาด | ระดับ API ที่รองรับเป็นครั้งแรก |
| drawText() | 18 |
| drawPosText() | 28 |
| drawTextOnPath() | 28 |
| รูปร่างง่ายๆ | 17 |
| รูปร่างที่ซับซ้อน | 28 |
| drawPath() | 28 |
| เลเยอร์เงา | 28 |
หากแอปพลิเคชันได้รับผลกระทบจากฟีเจอร์ที่ขาดหายไปหรือข้อจำกัดเหล่านี้
คุณสามารถปิดการเร่งด้วยฮาร์ดแวร์สำหรับส่วนที่ได้รับผลกระทบของ
แอปพลิเคชันได้โดยเรียกใช้ setLayerType(View.LAYER_TYPE_SOFTWARE, null)
วิธีนี้ช่วยให้คุณยังคงใช้ประโยชน์จากการเร่งฮาร์ดแวร์ได้ทุกที่
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีเปิดและปิดใช้การเร่งด้วยฮาร์ดแวร์ในระดับต่างๆ ในแอปพลิเคชันได้ที่ควบคุมการเร่งด้วยฮาร์ดแวร์
ดูเลเยอร์
ใน Android ทุกเวอร์ชัน วิวมีความสามารถในการแสดงผลลงในบัฟเฟอร์นอกหน้าจอ
โดยใช้แคชการวาดของวิว หรือใช้ Canvas.saveLayer บัฟเฟอร์นอกหน้าจอหรือเลเยอร์มีประโยชน์หลายอย่าง คุณสามารถใช้เพื่อเพิ่มประสิทธิภาพเมื่อเคลื่อนไหวมุมมองที่ซับซ้อนหรือใช้เอฟเฟกต์การจัดองค์ประกอบ
เช่น คุณสามารถใช้เอฟเฟกต์จางโดยใช้
Canvas.saveLayer เพื่อแสดงผลมุมมองชั่วคราวในเลเยอร์ แล้วคอมโพสิต
กลับบนหน้าจอด้วยปัจจัยความทึบ
ตั้งแต่ Android 3.0 (ระดับ API 11) เป็นต้นไป คุณจะควบคุมวิธีและเวลาในการใช้เลเยอร์ด้วยเมธอด View.setLayerType ได้มากขึ้น API นี้ใช้พารามิเตอร์ 2 รายการ ได้แก่ ประเภทเลเยอร์ที่ต้องการใช้และออบเจ็กต์ Paint
ที่ไม่บังคับซึ่งอธิบายวิธีคอมโพสเลเยอร์ คุณใช้พารามิเตอร์
Paint เพื่อใช้ตัวกรองสี โหมดการผสมพิเศษ หรือ
ความทึบกับเลเยอร์ได้ มุมมองสามารถใช้เลเยอร์ประเภทใดประเภทหนึ่งต่อไปนี้
LAYER_TYPE_NONE: มุมมองจะแสดงผลตามปกติและไม่ได้สำรองข้อมูลโดย บัฟเฟอร์นอกหน้าจอ นี่คือลักษณะการทำงานเริ่มต้นLAYER_TYPE_HARDWARE: มุมมองจะแสดงผลในฮาร์ดแวร์เป็นเท็กซ์เจอร์ฮาร์ดแวร์ หากแอปพลิเคชันใช้การเร่งด้วยฮาร์ดแวร์ หากแอปพลิเคชันไม่ได้ เร่งด้วยฮาร์ดแวร์ เลเยอร์ประเภทนี้จะทำงานเหมือนกับLAYER_TYPE_SOFTWARELAYER_TYPE_SOFTWARE: ระบบจะแสดงผลมุมมองในซอฟต์แวร์เป็นบิตแมป
ประเภทเลเยอร์ที่คุณใช้จะขึ้นอยู่กับเป้าหมายของคุณ ดังนี้
ประสิทธิภาพ: ใช้ประเภทเลเยอร์ฮาร์ดแวร์เพื่อแสดงผลมุมมองเป็นเท็กซ์เจอร์ฮาร์ดแวร์ เมื่อแสดงผลมุมมองเป็นเลเยอร์แล้ว ระบบจะไม่ต้องเรียกใช้โค้ดการวาดจนกว่ามุมมองจะเรียก
invalidateจากนั้นคุณจะใช้ภาพเคลื่อนไหวบางอย่าง เช่น ภาพเคลื่อนไหวแบบอัลฟ่า กับเลเยอร์ได้โดยตรง ซึ่งเป็นวิธีที่มีประสิทธิภาพมากสำหรับ GPUเอฟเฟกต์ภาพ: ใช้เลเยอร์ประเภทฮาร์ดแวร์หรือซอฟต์แวร์และ
Paintเพื่อใช้การปรับแต่งภาพพิเศษกับมุมมอง เช่น คุณวาดภาพวิวเป็นขาวดำได้โดยใช้ColorMatrixColorFilterความเข้ากันได้: ใช้ประเภทเลเยอร์ซอฟต์แวร์เพื่อบังคับให้แสดงมุมมองใน ซอฟต์แวร์ หากมุมมองที่เร่งด้วยฮาร์ดแวร์ (เช่น หากทั้งแอปพลิเคชันเร่งด้วยฮาร์ดแวร์) มีปัญหาในการแสดงผล นี่เป็นวิธีง่ายๆ ในการหลีกเลี่ยงข้อจำกัดของไปป์ไลน์การแสดงผลฮาร์ดแวร์
ดูเลเยอร์และภาพเคลื่อนไหว
เลเยอร์ฮาร์ดแวร์จะแสดงภาพเคลื่อนไหวได้เร็วและราบรื่นขึ้นเมื่อแอปพลิเคชัน
มีการเร่งด้วยฮาร์ดแวร์ การเรียกใช้ภาพเคลื่อนไหวที่ 60 เฟรมต่อวินาทีอาจทำไม่ได้เสมอไปเมื่อสร้างภาพเคลื่อนไหวของมุมมองที่ซับซ้อนซึ่งออกคำสั่งการวาดภาพจำนวนมาก ปัญหานี้สามารถแก้ไขได้โดยใช้เลเยอร์ฮาร์ดแวร์เพื่อแสดงผลมุมมอง
ไปยังเท็กซ์เจอร์ฮาร์ดแวร์ จากนั้นจะใช้พื้นผิวของฮาร์ดแวร์เพื่อทำให้
มุมมองเคลื่อนไหวได้ ซึ่งจะช่วยให้มุมมองไม่ต้องวาดซ้ำอยู่ตลอดเวลาเมื่อ
มีการทำให้เคลื่อนไหว ระบบจะไม่วาดมุมมองใหม่ เว้นแต่คุณจะเปลี่ยนพร็อพเพอร์ตี้ของมุมมอง
ซึ่งจะเรียกใช้ invalidate หรือหากคุณเรียกใช้ invalidate ด้วยตนเอง หาก
คุณเรียกใช้ภาพเคลื่อนไหวในแอปพลิเคชันและไม่ได้รับผลลัพธ์ที่ราบรื่น
ตามที่ต้องการ ให้ลองเปิดใช้เลเยอร์ฮาร์ดแวร์ในมุมมองที่มีภาพเคลื่อนไหว
เมื่อมุมมองได้รับการสนับสนุนจากเลเยอร์ฮาร์ดแวร์ ระบบจะจัดการพร็อพเพอร์ตี้บางอย่างของมุมมอง ด้วยวิธีที่เลเยอร์นั้นประกอบกันบนหน้าจอ การตั้งค่าพร็อพเพอร์ตี้เหล่านี้จะมีประสิทธิภาพเนื่องจากไม่จำเป็นต้องลบล้างและวาดมุมมองใหม่ รายการต่อไปนี้คือพร็อพเพอร์ตี้ที่มีผลต่อวิธี การคอมโพสเลเยอร์ การเรียกใช้ตัวตั้งค่าสำหรับพร็อพเพอร์ตี้เหล่านี้จะส่งผลให้เกิดการลบล้างที่เหมาะสมที่สุด และไม่มีการวาดมุมมองเป้าหมายใหม่
alpha: เปลี่ยนความทึบแสงของเลเยอร์x,y,translationX,translationY: เปลี่ยนตำแหน่งของเลเยอร์scaleX,scaleY: เปลี่ยนขนาดเลเยอร์rotation,rotationX,rotationY: เปลี่ยนการวางแนวของเลเยอร์ในพื้นที่ 3 มิติpivotX,pivotY: เปลี่ยนต้นทางการเปลี่ยนรูปแบบของเลเยอร์
พร็อพเพอร์ตี้เหล่านี้คือชื่อที่ใช้เมื่อสร้างภาพเคลื่อนไหวของมุมมองด้วย
ObjectAnimator หากต้องการเข้าถึงพร็อพเพอร์ตี้เหล่านี้ ให้เรียกใช้ตัวตั้งค่าหรือตัวรับค่าที่เหมาะสม เช่น หากต้องการแก้ไขพร็อพเพอร์ตี้ alpha ให้เรียกใช้
setAlpha ข้อมูลโค้ดต่อไปนี้แสดงวิธีที่มีประสิทธิภาพที่สุดในการ
หมุนมุมมองใน 3 มิติรอบแกน Y
Kotlin
view.setLayerType(View.LAYER_TYPE_HARDWARE, null) ObjectAnimator.ofFloat(view, "rotationY", 180f).start()
Java
view.setLayerType(View.LAYER_TYPE_HARDWARE, null); ObjectAnimator.ofFloat(view, "rotationY", 180).start();
เนื่องจากเลเยอร์ฮาร์ดแวร์ใช้หน่วยความจำวิดีโอ เราจึงขอแนะนำอย่างยิ่งให้คุณ เปิดใช้เลเยอร์ดังกล่าวเฉพาะในระยะเวลาของภาพเคลื่อนไหวเท่านั้น แล้วปิดใช้หลังจาก ภาพเคลื่อนไหวเสร็จสิ้น คุณทำได้โดยใช้เครื่องมือตรวจหาเหตุการณ์ของภาพเคลื่อนไหว
Kotlin
view.setLayerType(View.LAYER_TYPE_HARDWARE, null) ObjectAnimator.ofFloat(view, "rotationY", 180f).apply { addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { view.setLayerType(View.LAYER_TYPE_NONE, null) } }) start() }
Java
view.setLayerType(View.LAYER_TYPE_HARDWARE, null); ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotationY", 180); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { view.setLayerType(View.LAYER_TYPE_NONE, null); } }); animator.start();
ดูข้อมูลเพิ่มเติมเกี่ยวกับภาพเคลื่อนไหวของพร็อพเพอร์ตี้ได้ที่ภาพเคลื่อนไหวของพร็อพเพอร์ตี้
กลเม็ดเคล็ดลับ
การเปลี่ยนไปใช้กราฟิก 2 มิติที่เร่งด้วยฮาร์ดแวร์จะช่วยเพิ่มประสิทธิภาพได้ทันที แต่คุณก็ยังควรออกแบบแอปพลิเคชันให้ใช้ GPU อย่างมีประสิทธิภาพโดยทำตามคำแนะนำต่อไปนี้
- ลดจำนวนมุมมองในแอปพลิเคชัน
- ยิ่งระบบต้องดึงข้อมูลยอดดูมากเท่าไร ระบบก็จะยิ่งทำงานช้าลงเท่านั้น ซึ่งมีผลกับไปป์ไลน์การแสดงผลซอฟต์แวร์ ด้วย การลดจำนวนมุมมองเป็นวิธีที่ง่ายที่สุดวิธีหนึ่งในการเพิ่มประสิทธิภาพ UI
- หลีกเลี่ยงการเบิกเงินเกินบัญชี
- อย่าวาดเลเยอร์ซ้อนกันมากเกินไป นำมุมมองที่ถูกบดบังโดยสมบูรณ์ ด้วยมุมมองทึบแสงอื่นๆ ที่อยู่ด้านบนออก หากต้องการวาดเลเยอร์หลายๆ เลเยอร์ที่ผสมกันอยู่ด้านบน ของกันและกัน ให้พิจารณารวมเลเยอร์เหล่านั้นเป็นเลเยอร์เดียว กฎง่ายๆ สำหรับฮาร์ดแวร์ปัจจุบัน คืออย่าลากพิกเซลบนหน้าจอต่อเฟรมมากกว่า 2.5 เท่า (พิกเซลโปร่งใสในบิตแมปจะนับรวมด้วย)
- อย่าสร้างออบเจ็กต์การแสดงผลในเมธอดการวาด
- ข้อผิดพลาดที่พบบ่อยคือการสร้าง
Paintใหม่หรือPathใหม่ทุกครั้งที่มีการเรียกใช้เมธอดการแสดงผล ซึ่งจะบังคับให้ตัวเก็บขยะทำงานบ่อยขึ้น และยังข้ามแคชและการเพิ่มประสิทธิภาพในไปป์ไลน์ฮาร์ดแวร์ด้วย - อย่าแก้ไขรูปร่างบ่อยเกินไป
- ระบบจะแสดงรูปร่าง เส้นทาง และวงกลมที่ซับซ้อน เช่น โดยใช้มาสก์พื้นผิว ทุกครั้งที่คุณสร้างหรือแก้ไขเส้นทาง ไปป์ไลน์ฮาร์ดแวร์จะสร้างมาสก์ใหม่ ซึ่งอาจมีค่าใช้จ่ายสูง
- อย่าแก้ไขบิตแมปบ่อยเกินไป
- ทุกครั้งที่คุณเปลี่ยนเนื้อหาของบิตแมป ระบบจะอัปโหลดเนื้อหานั้นอีกครั้งเป็นเท็กซ์เจอร์ GPU ในครั้งถัดไปที่คุณวาด
- ใช้เวอร์ชันอัลฟ่าอย่างระมัดระวัง
- เมื่อทำให้มุมมองโปร่งแสงโดยใช้
setAlpha,AlphaAnimationหรือObjectAnimatorระบบจะ แสดงผลในบัฟเฟอร์นอกหน้าจอ ซึ่งจะเพิ่มอัตราการวาดที่จำเป็นเป็น 2 เท่า เมื่อใช้ค่าอัลฟ่า กับมุมมองขนาดใหญ่มาก ให้พิจารณาตั้งค่าประเภทเลเยอร์ของมุมมองเป็นLAYER_TYPE_HARDWARE