การเร่งฮาร์ดแวร์ (มุมมอง)

แนวคิดและการใช้งาน 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 ขั้นตอนต่อไปนี้

  1. ทำให้ลำดับชั้นไม่ถูกต้อง
  2. วาดลำดับชั้น

เมื่อใดก็ตามที่แอปพลิเคชันต้องอัปเดตส่วนหนึ่งของ UI แอปพลิเคชันจะเรียกใช้ invalidate() (หรือตัวแปรอย่างใดอย่างหนึ่ง) ในมุมมองใดก็ตามที่มีการเปลี่ยนแปลง เนื้อหา ข้อความการลบล้างจะเผยแพร่ไปจนถึงลำดับชั้นการแสดงผลเพื่อคำนวณภูมิภาคของหน้าจอที่ต้องวาดใหม่ (ภูมิภาคที่มีการแก้ไข) จากนั้นระบบ Android จะวาดมุมมองใดๆ ในลำดับชั้นที่ ตัดกับรีเจียนที่ต้องอัปเดต อย่างไรก็ตาม โมเดลการวาดภาพนี้มีข้อเสีย 2 ประการ ดังนี้

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

  • ปัญหาที่ 2 คือโมเดลการวาดอาจซ่อนข้อบกพร่องในแอปพลิเคชันของคุณ เนื่องจากระบบ Android จะวาดมุมมองใหม่เมื่อมุมมองตัดกับพื้นที่ที่ต้องวาดใหม่ มุมมองที่มีเนื้อหาที่คุณเปลี่ยนแปลงอาจถูกวาดใหม่แม้ว่าจะไม่ได้เรียกใช้ invalidate ในมุมมองนั้นก็ตาม เมื่อเกิดกรณีเช่นนี้ คุณจะต้องอาศัย การลบล้างมุมมองอื่นเพื่อให้ได้ลักษณะการทำงานที่เหมาะสม ลักษณะการทำงานนี้ อาจเปลี่ยนแปลงทุกครั้งที่คุณแก้ไขแอปพลิเคชัน ด้วยเหตุนี้ คุณจึงควรเรียกใช้ invalidate ในมุมมองที่กำหนดเองทุกครั้งที่แก้ไขข้อมูล หรือสถานะที่ส่งผลต่อโค้ดการวาดของมุมมอง

โมเดลการวาดภาพที่มีการเร่งด้วยฮาร์ดแวร์

ระบบ Android ยังคงใช้ invalidate และ draw เพื่อขอ อัปเดตหน้าจอและแสดงผลวิว แต่จะจัดการการวาดจริงแตกต่างกัน ระบบ Android จะบันทึกคำสั่งการวาดไว้ในรายการที่แสดง ซึ่งมีเอาต์พุตของโค้ดการวาดของลำดับชั้นของ View แทนที่จะเรียกใช้คำสั่งการวาดทันที การเพิ่มประสิทธิภาพอีกอย่างคือระบบ Android จะต้องบันทึกและอัปเดตรายการแสดงผลสำหรับมุมมองที่ทำเครื่องหมายว่ามีการแก้ไขโดยการเรียก invalidate เท่านั้น มุมมองที่ยังไม่ถือว่าไม่ถูกต้องสามารถวาดใหม่ได้ โดยการออกรายการที่แสดงที่บันทึกไว้ก่อนหน้านี้อีกครั้ง โมเดลการวาดภาพใหม่ มี 3 ขั้นตอนดังนี้

  1. ทำให้ลำดับชั้นไม่ถูกต้อง

  2. บันทึกและอัปเดตรายการที่แสดง

  3. วาดรายการที่แสดง

โมเดลนี้ทำให้คุณไม่สามารถพึ่งพามุมมองที่ตัดกับพื้นที่ที่เปลี่ยนแปลงเพื่อเรียกใช้เมธอด draw ได้ หากต้องการให้ระบบ Android บันทึกรายการแสดงผลของ View คุณต้องเรียกใช้ invalidate การลืมทำเช่นนี้ จะทำให้มุมมองดูเหมือนเดิมแม้ว่าจะมีการเปลี่ยนแปลงแล้วก็ตาม

การใช้รายการแสดงยังช่วยเพิ่มประสิทธิภาพของภาพเคลื่อนไหวด้วย เนื่องจากเมื่อตั้งค่าพร็อพเพอร์ตี้ที่เฉพาะเจาะจง เช่น อัลฟ่าหรือการหมุน คุณไม่จำเป็นต้องทำให้มุมมองเป้าหมายไม่ถูกต้อง (ระบบจะดำเนินการโดยอัตโนมัติ) การเพิ่มประสิทธิภาพนี้จะมีผลกับ มุมมองที่มีรายการแสดงผลด้วย (มุมมองใดก็ได้เมื่อแอปพลิเคชันของคุณเป็นฮาร์ดแวร์ เร่งความเร็ว) เช่น สมมติว่ามี LinearLayout ที่มี ListView อยู่เหนือ Button รายการที่แสดงสำหรับ LinearLayout มีลักษณะดังนี้

  • DrawDisplayList(ListView)
  • DrawDisplayList(Button)

สมมติว่าตอนนี้คุณต้องการเปลี่ยนความทึบของ ListView หลังจากเรียกใช้ setAlpha(0.5f) ใน ListView แล้ว ตอนนี้รายการที่แสดงจะมีข้อมูลต่อไปนี้

  • SaveLayerAlpha(0.5)

  • DrawDisplayList(ListView)

  • Restore

  • DrawDisplayList(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_SOFTWARE

  • LAYER_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