เวลาเริ่มต้นของแอป

ผู้ใช้คาดหวังให้แอปโหลดได้เร็วและตอบสนองได้ดี แอปที่ใช้เวลาในการเริ่มต้นช้าไม่เป็นไปตามความคาดหวังนี้และอาจทำให้ผู้ใช้ผิดหวัง ประสบการณ์การใช้งานที่ไม่ดีประเภทนี้อาจทำให้ผู้ใช้ให้คะแนนแอปของคุณต่ำใน Play Store หรืออาจเลิกใช้แอปไปเลย

หน้านี้ให้ข้อมูลเพื่อช่วยเพิ่มประสิทธิภาพเวลาเปิดของแอป ซึ่งรวมถึงภาพรวมของกระบวนการภายในของการเปิดตัว วิธีโปรไฟล์ประสิทธิภาพการเริ่มต้น และปัญหาเกี่ยวกับเวลาเริ่มต้นที่พบได้ทั่วไปพร้อมเคล็ดลับในการแก้ไข

ทําความเข้าใจสถานะการเริ่มต้นของแอป

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

เราขอแนะนําให้เพิ่มประสิทธิภาพโดยอิงตามสมมติฐานของ Cold Start เสมอ ซึ่งจะช่วยปรับปรุงประสิทธิภาพของ Warm Start และ Hot Start ด้วย

หากต้องการเพิ่มประสิทธิภาพแอปให้เริ่มต้นอย่างรวดเร็ว คุณควรทำความเข้าใจสิ่งที่เกิดขึ้นที่ระดับระบบและแอป รวมถึงวิธีที่ระบบและแอปโต้ตอบกันในแต่ละสถานะ

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

Cold Start

Cold Start หมายถึงการเริ่มทำงานตั้งแต่ต้นของแอป ซึ่งหมายความว่าจนกว่าจะเริ่มต้นกระบวนการนี้ กระบวนการของระบบจะสร้างกระบวนการของแอป Cold Start จะเกิดขึ้นในกรณีต่างๆ เช่น แอปเปิดขึ้นเป็นครั้งแรกนับตั้งแต่ที่อุปกรณ์บูต หรือนับตั้งแต่ที่ระบบปิดแอป

การเริ่มต้นประเภทนี้ทำให้เกิดความท้าทายมากที่สุดในการลดเวลาในการเริ่มต้นใช้งาน เนื่องจากระ���บและแอปต้องทำงานมากกว่าการเปิดในสถานะอื่นๆ

ในช่วงเริ่มต้นของ Cold Start ระบบจะมีงาน 3 อย่างต่อไปนี้

  1. โหลดและเปิดแอป
  2. แสดงหน้าต่างเริ่มต้นว่างสำหรับแอปทันทีหลังจากเปิด
  3. กระบวนการสร้างแอป

ทันทีที่ระบบสร้างกระบวนการของแอป กระบวนการของแอปจะมีหน้าที่รับผิดชอบในขั้นตอนถัดไป ดังนี้

  1. สร้างออบเจ็กต์แอป
  2. เปิดชุดข้อความหลัก
  3. สร้างกิจกรรมหลัก
  4. เพิ่มยอดดู
  5. จัดเลย์เอาต์หน้าจอ
  6. ดึงข้อมูลครั้งแรก

เมื่อกระบวนการของแอปวาดภาพแรกเสร็จสมบูรณ์แล้ว กระบวนการของระบบจะสลับหน้าต่างเบื้องหลังที่แสดงอยู่ออก แล้วแทนที่ด้วยกิจกรรมหลัก เมื่อถึงขั้นตอนนี้ ผู้ใช้จะเริ่มใช้แอปได้

รูปที่ 1 แสดงวิธีที่ระบบและแอปส่งต่องานระหว่างกัน

รูปที่ 1 ภาพแสดงส่วนสําคัญของการเปิดแอปแบบ Cold Start

ปัญหาด้านประสิทธิภาพอาจเกิดขึ้นระหว่างการสร้างแอปและการสร้างกิจกรรม

การสร้างแอป

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

หากคุณลบล้าง Application.onCreate() ในแอปของคุณเอง ระบบจะเรียกใช้เมธอด onCreate() บนออบเจ็กต์แอป หลังจากนั้น แอปจะสร้างเทรดหลักหรือที่เรียกว่าเทรด UI และมอบหมายให้สร้างกิจกรรมหลัก

จากจุดนี้ กระบวนการระดับระบบและแอปจะดำเนินไปตามระยะต่างๆ ของวงจรชีวิตของแอป

การสร้างกิจกรรม

หลังจากกระบวนการของแอปสร้างกิจกรรมแล้�� กิจกรรมจะดําเนินการต่อไปนี้

  1. เริ่มต้นค่า
  2. เรียกเครื่องมือสร้าง
  3. เรียกเมธอดการเรียกกลับ เช่น Activity.onCreate() ที่เหมาะสมกับสถานะวงจรชีวิตของกิจกรรมปัจจุบัน

โดยทั่วไปแล้ว เมธอด onCreate() จะมีผลต่อเวลาในการโหลดมากที่สุด เนื่องจากจะทํางานโดยมีค่าใช้จ่ายเพิ่มเติมสูงสุด ซึ่งได้แก่ การโหลดและการขยายวิว และการจัดเตรียมออบเจ็กต์ที่จําเป็นสําหรับให้กิจกรรมทํางาน

Warm Start

การเริ่มแอปแบบ Warm Start ประกอบด้วยการดำเนินการชุดย่อยที่เกิดขึ้นระหว่างการเริ่มแอปแบบ Cold Start ในขณะเดียวกัน วิธีการนี้ยังทำให้เกิดค่าใช้จ่ายเพิ่มเติมมากกว่าการเริ่มต้นแบบ Hot Start สถานะที่เป็นไปได้หลายสถานะอาจถือเป็นการเริ่มต้นแบบอุ่นเครื่อง เช่น สถานะต่อไปนี้

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

  • ระบบจะย้ายแอปของคุณออกจากหน่วยความจำ จากนั้นผู้ใช้จะเปิดแอปอีกครั้ง กระบวนการและกิจกรรมต้องเริ่มต้นใหม่ แต่งานอาจได้รับประโยชน์บางอย่างจากกลุ่มสถานะอินสแตนซ์ที่บันทึกไว้ซึ่งส่งไปยัง onCreate()

Hot Start

การเริ่มแอปแบบ Hot Start จะมีค่าใช้จ่ายเพิ่มเติมต่ำกว่าการเริ่มแอปแบบ Cold Start ในการเริ่มต้นแบบร้อน ระบบจะนำกิจกรรมของคุณไปไว้ที่เบื้องหน้า หากกิจกรรมทั้งหมดของแอปยังคงอยู่ในหน่วยความจํา แอปจะหลีกเลี่ยงการเริ่มต้นวัตถุ การจัดวาง และการเรนเดอร์ซ้ำได้

อย่างไรก็ตาม หากมีการล้างหน่วยความจำบางส่วนเพื่อตอบสนองต่อเหตุการณ์การลดหน่วยความจำ เช่น onTrimMemory() จะต้องสร้างออบเจ็กต์เหล่านี้ขึ้นมาใหม่เพื่อตอบสนองต่อเหตุการณ์การเริ่มต้นอย่างรวดเร็ว

การเริ่มต้นแบบร้อนจะแสดงลักษณะการทำงานบ��หน้าจอเหมือนกับสถานการณ์การเริ่มต้นแบบเย็น กระบวนการของระบบจะแสดงหน้าจอว่างเปล่าจนกว่าแอปจะแสดงผลกิจกรรมเสร็จ

รูปที่ 2 แผนภาพที่มีสถานะการเริ่มต้นต่างๆ และกระบวนการที่เกี่ยวข้อง โดยแต่ละสถานะจะเริ่มต้นจากเฟรมแรก

วิธีระบุการเริ่มต้นของแอปใน Perfetto

หากต้องการแก้ไขข้อบกพร่องเกี่ยวกับการเริ่มต้นของแอป คุณควรระบุสิ่งที่รวมอยู่ในระยะเริ่มต้นของแอป หากต้องการระบุระยะเริ่มต้นของแอปทั้งหมดใน Perfetto ให้ทําตามขั้นตอนต่อไปนี้

  1. ใน Perfetto ให้ค้นหาแถวที่มีเมตริกที่มาจาก "การเริ่มต้นแอป Android" หากไม่เห็น ให้ลองบันทึกการติดตามโดยใช้แอปการติดตามระบบในอุปกรณ์

    รูปที่ 3. ข้อมูลเมตริกที่ได้จาก "การเริ่มต้นแอป Android" ใน Perfetto
  2. คลิกส่วนที่เกี่ยวข้องแล้วกด m เพื่อเลือกส่วน วงเล็บจะปรากฏรอบๆ ส่วนของภาพและระบุระยะเวลา ระยะเวลาจะแสดงในแท็บการเลือกปัจจุบันด้วย

  3. ปักหมุดแถวแอป Android ที่เริ่มต้นโดยคลิกไอคอนปักหมุด ซึ่งจะปรากฏขึ้นเมื่อคุณวางเคอร์เซอร์เหนือแถว

  4. เลื่อนไปที่แถวที่มีแอปที่เป็นปัญหา แล้วคลิกเซลล์แรกเพื่อขยายแถว

  5. ซูมเข้าชุดข้อความหลัก ซึ่งมักจะอยู่ด้า��������������ด w (กด s, a, d เพื่อซูมออก เลื่อนไปทางซ้าย และเลื่อนไปทางขวาตามลำดับ)

    รูปที่ 4. ข้อมูลเมตริกที่ได้จาก "การเริ่มต้นแอป Android" ถัดจากเทรดหลักของแอป
  6. ส่วนเมตริกที่ได้จากข้อมูลที่มีอยู่ช่วยให้คุณเห็นสิ่งที่รวมอยู่ในการเริ่มต้นแอปได้อย่างชัดเจนยิ่งขึ้น คุณจึงแก้ไขข้อบกพร่องได้ละเอียดยิ่งขึ้น

ใช้เมตริกเพื่อตรวจสอบและปรับปรุงสตาร์ทอัป

หากต้องการวิเคราะห์ประสิทธิภาพเวลาเริ่มต้นอย่างถูกต้อง คุณสามารถติดตามเมตริกที่แสดงเวลาที่แอปใช้ในการเริ่มต้น Android มีวิธีต่างๆ ในการแจ้งให้คุณทรา���ว่าแอปมีปัญหาและช่วยคุณวิเคราะห์ปัญหา Android Vitals สามารถแจ้งเตือนคุณเมื่อมีปัญหาเกิดขึ้น และเครื่องมือการวินิจฉัยจะช่วยคุณวินิจฉัยปัญหาได้

ประโยชน์ของการใช้เมตริกสําหรับธุรกิจเริ่มต้น

Android ใช้เมตริกเวลาที่ใช้ในการแสดงผลครั้งแรก (TTID) และเวลาที่ใช้ในการแสดงผลจนเต็ม (TTFD) เพื่อเพิ่มประสิทธิภาพการเริ่มต้นแอปแบบ Cold และ Warm Android Runtime (ART) ใช้ข้อมูลจากเมตริกเหล่านี้เพื่อคอมไพล์โค้ดล่วงหน้าอย่างมีประสิทธิภาพเพื่อการเพิ่มประสิทธิภาพของการใช้งานในอนาคต

การเริ่มต้นที่เร็วขึ้นทําให้ผู้ใช้โต้ตอบกับแอปได้นานขึ้น ซึ่งจะช่วยลดจํานวนครั้งที่ผู้ใช้ออกจากแอปก่อนเวลาอันควร รีสตาร์ทอินสแตนซ์ หรือไปยังแอปอื่น

Android Vitals

Android Vitals ช่วยปรับปรุงประสิทธิภาพของแอปได้โดยแจ้งเตือนคุณใน Play Console เมื่อเวลาเริ่มต้นของแอปนานเกินไป

Android Vitals จะถือว่าเวลาเริ่มต้นของแอปต่อไปนี้นานเกินไป

  • การเริ่มต้นจากต้นใช้เวลา 5 วินาทีขึ้นไป
  • การเริ่มต้นอุ่นเครื่องใช้เวลา 2 วินาทีขึ้นไป
  • การเริ่มต้นร้อนใช้เวลา 1.5 วินาทีขึ้นไป

Android Vitals ใช้เมตริกเวลาที่ใช้ในการแสดงผลครั้งแรก (TTID) ดูข้อ��ูลเกี่ยวกับวิธีที่ Google Play รวบรวมข้อมูล Android Vitals ได้ที่เอกสารประกอบของ Play Console

เวลาที่ใช้ในการเริ่มแสดงผล

เวลาที่ใช้ในการเริ่มแสดงผล (TTID) คือระยะเวลาที่ใช้ในการแสดงเฟรมแรกของ UI ของแอป เมตริกนี้วัดเวลาที่แอปใช้ในการสร้างเฟรมแรก ซึ่งรวมถึงการเริ่มต้นกระบวนการระหว่างการเริ่มต้นแบบ Cold การเริ่มสร้างกิจกรรมระหว่างการเริ่มต้นแบบ Cold หรือแบบ Warm และการแสดงเฟรมแรก การทำให้ TTID ของแอปต่ำอยู่เสมอจะช่วยปรับปรุงประสบการณ์ของผู้ใช้ด้วยการช่วยให้ผู้ใช้เห็นการเปิดตัวแอปอย่างรวดเร็ว Android Framework จะรายงาน TTID โดยอัตโนมัติสําหรับทุกแอป เมื่อเพิ่มประสิทธิภาพเพื่อเปิดแอป เราขอแนะนําให้ใช้ reportFullyDrawn เพื่อรับข้อมูลจนถึง TTFD

TTID จะวัดเป็นค่าเวลาซึ่งแสดงเวลาผ่านไปทั้งหมดที่รวมลําดับเหตุการณ์ต่อไปนี้

  • การเริ่มกระบวนการ
  • กำลังเริ่มต้นออบเจ็กต์
  • การสร้างและเริ่มต้นกิจกรรม
  • การขยายเลย์เอาต์
  • การวาดแอปเป็นครั้งแรก

เรียกข้อมูล TTID

หากต้องการค้นหา TTID ให้ค้นหาในเครื่องมือบรรทัดคำสั่ง Logcat สำหรับบรรทัดเอาต์พุตที่มีค่าชื่อ Displayed ค่านี้คือ TTID และมีลักษณะคล้ายกับตัวอย่างต่อไปนี้ ซึ่ง TTID คือ 3s534ms

ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms

หากต้องการค้นหา TTID ใน Android Studio ให้ปิดใช้ตัวกรองในมุมมอง Logcat จากเมนูแบบเลื่อนลงของตัวกรอง แล้วค้นหาเวลา Displayed ดังที่แสดงในรูปที่ 5 คุณต้องปิดใช้ตัวกรองเนื่องจากเซิร์ฟเวอร์ของระบบจะแสดงบันทึกนี้ ไม่ใช่แอป

รูปที่ 5 ตัวกรองที่ปิด��ช้และค่า Displayed ใน logcat

เมตริก Displayed ในเอาต์พุต Logcat ไม่จำเป็นต้องจับเวลาจนกว่าระบบจะโหลดและแสดงทรัพยากรทั้งหมด โดยจะไม่รวมทรัพยากรที่ไม่ได้อ้างอิงในไฟล์เลย์เอาต์หรือที่แอปสร้างขึ้นเป็นส่วนหนึ่งของการเริ่มต้นออบเจ็กต์ โดยจะไม่รวมทรัพยากรเหล่านี้เนื่องจากการโหลดเป็นกระบวนการในบรรทัดและไม่บล็อกการแสดงผลเริ่มต้นของแอป

บางครั้งบรรทัด Displayed ในเอาต์พุต Logcat จะมีช่องเพิ่มเติมสำหรับเวลาทั้งหมด เช่น

ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms (total +1m22s643ms)

ในกรณีนี้ การวัดครั้งแรกจะมีไว้สําหรับกิจกรรมที่ดึงข้อมูลเป็นครั้งแรกเท่านั้น การวัดเวลา total จะเริ่มที่จุดเริ่มต้นของกระบวนการแอปและอาจรวมกิจกรรมอื่นที่เริ่มต้นก่อนแต่ไม่ได้แสดงอะไรบนหน้าจอ การวัดเวลา total จะแสดงเฉพาะในกรณีที่มีความแตกต่างระหว่างกิจกรรมเดียวกับเวลาเริ่มต้นทั้งหมด

เราขอแนะนำให้ใช้ Logcat ใน Android Studio แต่หากคุณไม่ได้ใช้ Android Studio ก็สามารถวัด TTID ได้โดยเรียกใช้แอปด้วยadb shell คำสั่งตัวจัดการกิจกรรม ตัวอย่างเช่น

adb [-d|-e|-s <serialNumber>] shell am start -S -W
com.example.app/.MainActivity
-c android.intent.category.LAUNCHER
-a android.intent.action.MAIN

เมตริก Displayed จะปรากฏในเอาต์พุต Logcat เหมือนเดิม หน้าต่างเทอร์มินัลจะแสดงข้อมูลต่อไปนี้

Starting: Intent
Activity: com.example.app/.MainActivity
ThisTime: 2044
TotalTime: 2044
WaitTime: 2054
Complete

อาร์กิวเมนต์ -c และ -a เป็นอาร์กิวเมนต์ที่ไม่บังคับและให้คุณระบุ <category> และ <action> ได้

เวลาที่ใช้ในการแสดงผลครบถ้วน

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

ระบบจะกำหนด TTID เมื่อ Choreographer เรียกใช้เมธอด onDraw() ของกิจกรรม และเมื่อทราบว่ามีการเรียกใช้เมธอดนี้เป็นครั้งแรก อย่างไรก็ตาม ระบบไม่ทราบว่าจะกำหนด TTFD เมื่อใด เนื่องจากแอปแต่ละแอปทำงานแตกต่างกัน หากต้องการระบุ TTFD แอปจะต้องส่งสัญญาณไปยังระบบเมื่อถึงสถานะวาดภาพเสร็จสมบูรณ์

เรียกข้อมูล TTFD

หากต้องการค้นหา TTFD ให้ส่งสัญญาณสถานะวาดภาพเสร็จสมบูรณ์โดยเรียกใช้เมธอด reportFullyDrawn() ของ ComponentActivity เมธอด reportFullyDrawn จะรายงานเมื่อแอปวาดภาพเสร็จสมบูรณ์และอยู่ในสถานะที่ใช้งานได้ TTFD คือเวลาที่ผ่านไปนับจากเวลาที่ระบบได้รับIntent การเริ่มแอปจนถึงเวลาที่เรียกใช้ reportFullyDrawn() หากไม่ได้เรียกใช้ reportFullyDrawn() ระบบจะไม่รายงานค่า TTFD

หากต้องการวัด TTFD ให้เรียกใช้ reportFullyDrawn() หลังจากที่คุณวาด UI และข้อมูลทั้งหมดเรียบร้อยแล้ว อย่าเรียก reportFullyDrawn() ก่อนที่ระบบจะวาดและแสดงกรอบเวลาของกิจกรรมแรกตามที่วัดได้เป็นครั้งแรก เนื่องจากระบบจะรายงานเวลาที่วัดได้ กล่าวคือ หากคุ���เรียกใช้ reportFullyDrawn() ก่อนที่ระบบจะตรวจพบ TTID ระบบจะรายงานทั้ง TTID และ TTFD เป็นค่าเดียวกัน และค่านี้คือค่า TTID

เมื่อคุณใช้ reportFullyDrawn() ทาง Logcat จะแสดงผลลัพธ์ดังตัวอย่างต่อไปนี้ ซึ่ง TTFD คือ 1s54ms

system_process I/ActivityManager: Fully drawn {package}/.MainActivity: +1s54ms

บางครั้งเอาต์พุต Logcat จะมีเวลา total ตามที่อธิบายไว้ในเวลาในการแสดงผลครั้งแรก

หากเวลาแสดงผลช้ากว่าที่ต้องการ ให้ลองระบุจุดคอขวดในกระบวนการเริ่มต้น

คุณสามารถใช้ reportFullyDrawn() เพื่อส่งสัญญาณสถานะวาดภาพเสร็จสมบูรณ์ในเคสพื้นฐานซึ่งคุณทราบว่าสถานะวาดภาพเสร็จสมบูรณ์แล้ว อย่างไรก็ตาม ในกรณีที่เธรดเบื้องหลังต้องทํางานเบื้องหลังให้เสร็จสมบูรณ์ก่อนจึงจะเข้าสู่สถานะวาดภาพเสร็จสมบูรณ์ได้ คุณจะต้องเลื่อนเวลา reportFullyDrawn() เพื่อให้การวัด TTFD แม่นยํายิ่งขึ้น ดูวิธีเลื่อนเวลา reportFullyDrawn() ได้ที่ส่วนต่อไปนี้

ปรับปรุงความแม่นยำของเวลาเริ่มต้น

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

ตัวอย่างเช่น หาก UI มีรายการแบบไดนามิก เช่น RecyclerView หรือรายการแบบ Lazy รายการนี้อาจสร้างขึ้นโดยงานเบื้องหลังที่เสร็จสมบูรณ์หลังจากวาดรายการเป็นครั้งแรก และหลังจาก UI ได้รับการระบุว่าวาดเสร็จแล้ว ในกรณีเช่นนี้ ประชากรของรายการจะไม่รวมอยู่ในการเปรียบเทียบ

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

FullyDrawnReporter จะไม่เรียกใช้เมธอด reportFullyDrawn() จนกว่าจะมีการเผยแพร่โปรแกรมรายงานที่เพิ่มทั้งหมด การเพิ่มผู้รายงานจนกว่ากระบวนการเบื้องหลังจะเสร็จสมบูรณ์จะรวมระยะเวลาที่ใช้ในการป้อนข้อมูลรายการไว้ในข้อมูลเวลาเริ่มต้นด้วย ซึ่งจะไม่เปลี่ยนลักษณะการทํางานของแอปสําหรับผู้ใช้ แต่จะทําให้ข้อมูลการเริ่มต้นระบบตามเวลารวมเวลาที่ใช้ในการป้อนข้อมูลรายการ ระบบจะไม่เรียกใช้ reportFullyDrawn() จนกว่างานทั้งหมดจะเสร็จสมบูรณ์ ไม่ว่าจะดำเนินการตามลำดับใดก็ตาม

ตัวอย่างต่อไปนี้แสดงวิธีเรียกใช้งานเบื้องหลังหลายรายการพร้อมกัน โดยแต่ละรายการจะลงทะเบียนผู้รายงานของตัวเอง

Kotlin

class MainActivity : ComponentActivity() {

    sealed interface ActivityState {
        data object LOADING : ActivityState
        data object LOADED : ActivityState
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            var activityState by remember {
                mutableStateOf(ActivityState.LOADING as ActivityState)
            }
            fullyDrawnReporter.addOnReportDrawnListener {
                activityState = ActivityState.LOADED
            }
            ReportFullyDrawnTheme {
                when(activityState) {
                    is ActivityState.LOADING -> {
                        // Display the loading UI.
                    }
                    is ActivityState.LOADED -> {
                        // Display the full UI.
                    }
                }
            }
            SideEffect {
                fullyDrawnReporter.addReporter()
                lifecycleScope.launch(Dispatchers.IO) {
                    // Perform the background operation.
                    fullyDrawnReporter.removeReporter()
                }
                fullyDrawnReporter.addReporter()
                lifecycleScope.launch(Dispatchers.IO) {
                    // Perform the background operation.
                    fullyDrawnReporter.removeReporter()
                }
            }
        }
    }
}

Java

public class MainActivity extends ComponentActivity {
    private FullyDrawnReporter fullyDrawnReporter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        fullyDrawnReporter = getFullyDrawnReporter();
        fullyDrawnReporter.addOnReportDrawnListener(() -> {
            // Trigger the UI update.
            return Unit.INSTANCE;
        });

        new Thread(new Runnable() {
            @Override
            public void run() {
                fullyDrawnReporter.addReporter();
                // Do the background work.
                fullyDrawnReporter.removeReporter();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                fullyDrawnReporter.addReporter();
                // Do the background work.
                fullyDrawnReporter.removeReporter();
            }
        }).start();
    }
}

หาก��อปใช้ Jetpack Compose คุณสามารถใช้ API ต่อไปนี้เพื่อระบุสถานะวาดภาพเสร็จสมบูรณ์

  • ReportDrawn: ระบุว่าคอมโพสิเบิลของคุณพร้อมสําหรับการโต้ตอบทันที
  • ReportDrawnWhen: ใช้พริเนกต์ เช่น list.count > 0 เพื่อบ่งบอกว่าคอมโพสิเบิลพร้อมสําหรับการโต้ตอบเมื่อใด
  • ReportDrawnAfter: ใช้เมธอดที่ระงับ ซึ่งเมื่อดำเนินการเสร็จแล้ว จะระบุว่าคอมโพสิเบิลของคุณพร้อมสำหรับการโต้ตอบ
ระบุจุดคอขวด

หากต้องการค้นหาจุดคอขวด คุณสามารถใช้เครื่องมือสร้างโปรไฟล์ CPU ของ Android Studio ดูข้อมูลเพิ่มเติมที่หัวข้อตรวจสอบกิจกรรมของ CPU ด้วยเครื่องมือวิเคราะห์โปรไฟล์ CPU

นอกจากนี้ คุณยังดูข้อมูลเชิงลึกเกี่ยวกับคอขวดที่อาจเกิดขึ้นผ่านการติดตามแบบอินไลน์ในonCreate()เมธอดของแอปและกิจกรรมได้ด้วย ดูข้อมูลเกี่ยวกับการติดตามแบบอินไลน์ได้จากเอกสารประกอบของฟังก์ชัน Trace และภาพรวมของการติดตามระบบ

แก้ปัญหาที่พบบ่อย

ส่วนนี้จะกล่าวถึงปัญหาหลายอย่างที่มักส่งผลต่อประสิทธิภาพการเริ่มต้นของแอป ปัญหาเหล่านี้เกี่ยวข้องกับการเริ่มต้นวัตถุแอปและกิจกรรม รวมถึงการโหลดหน้าจอเป็นหลัก

การสร้างอินสแตนซ์แอปจำนวนมาก

ประสิทธิภาพการเปิดตัวอาจลดลงเมื่อโค้ดของคุณลบล้างออบเจ็กต์ Application และดำเนินการที่หนักหน่วงหรือตรรกะที่ซับซ้อนเมื่อเริ่มต้นออบเจ็กต์นั้น แอปของคุณอาจเสียเวลาในระหว่างการเริ่มต้น หากคลาสย่อย Application ทำการเริ่มต้นที่ไม่จําเป็น

การ���ัดเตรียมข้อมูลบางอย่างอาจไม่จำเป็นเลย เช่น เมื่อจัดเตรียมข้อมูลสถานะสำหรับกิจกรรมหลักเมื่อแอปเริ่มทำงานจริงเพื่อตอบสนองต่อ Intent เมื่อใช้ Intent แอปจะใช้เฉพาะข้อมูลสถานะที่เริ่มต้นไว้ก่อนหน้านี้เพียงชุดย่อยเท่านั้น

ปัญหาอื่นๆ ที่เกิดขึ้นระหว่างการเริ่มต้นแอป ได้แก่ เหตุการณ์การเก็บขยะที่มีผลกระทบหรือมีจำนวนมาก หรือ I/O ของดิสก์ที่เกิดขึ้นพร้อมกันกับการเริ่มต้น ซึ่งจะบล็อกกระบวนการเริ่มต้นเพิ่มเติม การเก็บขยะเป็นสิ่งที่ต้องพิจารณาเป็นพิเศษสำหรับรันไทม์ Dalvik ส่วนรันไทม์ Android (ART) จะทำการรวบรวมขยะพร้อมกันเพื่อลดผลกระทบของการดำเนินการดังกล่าว

วินิจฉัยปัญหา

คุณสามารถใช้การติดตามเมธอดหรือการติดตามในบรรทัดเพื่อพยายามวิเคราะห์ปัญหา

การติดตามเมธอด

การรันเครื่องมือวิเคราะห์ CPU แสดงให้เห็นว่าท้ายที่สุดแล้วเมธอด callApplicationOnCreate() จะเรียกเมธอด com.example.customApplication.onCreate หากเครื่องมือแสดงว่าเมธอดเหล่านี้ใช้เวลานานในการดำเนินการให้เสร็จสิ้น ให้ตรวจสอบเพิ่มเติมเพื่อดูว่าเกิดอะไรขึ้น

การติดตามในบรรทัด

ใช้การติดตามอินไลน์เพื่อตรวจสอบสาเหตุที่เป็นไปได้ ซึ่งรวมถึงรายการต่อไปนี้

  • ฟังก์ชัน onCreate() เริ่มต้นของแอป
  • ออบเจ็กต์แบบ Singleton ทั่วโลกที่แอปของคุณเริ่มต้น
  • I/O ของดิสก์ การแปลงข้อมูลแบบย้อนกลับ หรือลูปที่ทำงานหนักซึ่งอาจเกิดขึ้นในช่วงคอขวด

วิธีแก้ปัญหา

ไม่ว่าจะมีปัญหาเกี่ยวกับการเริ่มต้นที่ไม่จำเป็นหรือ I/O ของดิสก์ ทางออกก็คือการเริ่มต้นแบบเลื่อนเวลา กล่าวคือ ให้เริ่มต้นวัตถุที่จำเป็นในทันทีเท่านั้น แทนที่จะสร้างออ��เจ็กต์แบบคงที่ส่วนกลาง ให้เปลี่ยนไปใช้รูปแบบ Singleton ซึ่งแอปจะเริ่มต้นออบเจ็กต์เฉพาะเ��ื่อต้องการใช้เป็นครั้งแรกเท่านั้น

นอกจากนี้ ให้พิจารณาใช้เฟรมเวิร์กการฉีดข้อมูล Dependency อย่าง Hilt ที่สร้างออบเจ็กต์และ Dependency เมื่อมีการฉีดข้อมูลเป็นครั้งแรก

หากแอปใช้ผู้ให้บริการเนื้อหาเพื่อเริ่มต้นคอมโพเนนต์แอปเมื่อเริ่มต้น ให้ลองใช้ไลบรารีการเริ่มต้นแอปแทน

การเริ่มต้นกิจกรรมที่หนัก

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

  • การขยายเลย์เอาต์ขนาดใหญ่หรือซับซ้อน
  • การบล็อกการวาดหน้าจอบนดิสก์หรือ I/O ของเครือข่าย
  • การโหลดและการถอดรหัสบิตแมป
  • แรสเตอร์ออบเจ็กต์ VectorDrawable
  • เริ่มต้นระบบของซับระบบอื่นๆ ของกิจกรรม

วินิจฉัยปัญหา

ในกรณีนี้ ทั้งการติดตามเมธอดและการติดตามในบรรทัดก็มีประโยชน์เช่นกัน

การติดตามเมธอด

เมื่อใช้เครื่องมือวิเคราะห์ CPU ให้สังเกตApplication ของแอป นั่นคือตัวสร้างคลาสย่อยและเมธอด com.example.customApplication.onCreate()

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

การติดตามในบรรทัด

ใช้การติดตามแบบอินไลน์เพื่อตรวจสอบสาเหตุที่เป็นไปได้ ซึ่งรวมถึงรายการต่อไปนี้

  • ฟังก์ชัน onCreate() เริ่มต้นของแอป
  • ออบเจ็กต์แบบ Singleton ทั่วโลกที่เริ่มต้น
  • I/O ของดิสก์ การแปลงข้อมูลแบบย้อนกลับ หรือลูปที่ทำงานหนักซึ่งอาจเกิดขึ้นในช่วงคอขวด

วิธีแก้ปัญหา

ปัญหาที่อาจเกิดขึ้นได้นั้นมีมากมาย แต่ปัญหาที่พบบ่อย 2 ข้อและวิธีแก้ไขมีดังนี้

  • ยิ่งลําดับชั้นของมุมมองมีขนาดใหญ่เท่าใด แอป��็ยิ่งใช้เวลาในการขยายนานขึ้นเท่านั้น ขั้นตอน 2 อย่างที่คุณทำได้เพื่อแก้ไขปัญหานี้ ได้แก่
    • ยุบลำดับชั้นมุมมองโดยลดเลย์เอาต์ที่ซ้ำซ้อนหรือซ้อนกัน
    • อย่าขยายส่วนต่างๆ ของ UI ที่ไม่จําเป็นต้องแสดงในระหว่างการเปิดตัว ให้ใช้ออบเจ็กต์ ViewStub เป็นตัวยึดตําแหน่งสำหรับลําดับชั้นย่อยแทนเพื่อให้แอปสามารถขยายตัวในเวลาที่เหมาะสมมากขึ้น
  • การทำอินทิลีเซชันทรัพยากรทั้งหมดในเธรดหลักยังอาจทำให้การเริ่มต้นทำงานช้าลงด้วย คุณสามารถแก้ไขปัญหานี้ได้โดยทำดังนี้
    • ย้ายการเริ่มต้นทรัพยากรทั้งหมดเพื่อให้แอปทํางานแบบเลื่อนเวลาในเธรดอื่น
    • ให้แอปโหลดและแสดงมุมมอง จากนั้นอัปเดตพร็อพเพอร์ตี้ภาพในภายหลังซึ่งขึ้นอยู่กับบิตแมปและทรัพยากรอื่นๆ

หน้าจอแนะนำที่กําหนดเอง

คุณอาจเห็นว่าระบบใช้เวลานานขึ้นระหว่างการเริ่มต้น หากก่อนหน้านี้คุณใช้วิธีใดวิธีหนึ่งต่อไปนี้เพื่อติดตั้งใช้งานหน้าจอแนะนำที่กําหนดเองใน Android 11 (API ระดับ 30) หรือเวอร์ชันก่อนหน้า

  • ใช้แอตทริบิวต์ธีม windowDisablePreview เพื่อปิดหน้าจอว่างเปล่าเริ่มต้นที่ระบบวาดขึ้นระหว่างการเปิดตัว
  • ใช้ Activity โดยเฉพาะ

ตั้งแต่ Android 12 เป็นต้นไป คุณจะต้องย้ายข้อมูลไปยัง SplashScreen API API นี้ช่วยให้เวลาเริ่มต้นเร็วขึ้นและให้คุณปรับแต่งหน้าจอแนะนำได้ดังนี้

นอกจากนี้ ไลบรารี compat ยังพอร์ต SplashScreen API ไปยังเวอร์ชันเก่าเพื่อให้ใช้งานร่วมกันได้แบบย้อนหลัง และสร้างรูปลักษณ์ที่สอดคล้องกับการแสดงภาพหน้าจอใน Android ทุกเวอร์ชัน

ดูรายละเอียดได้จากคำแนะนำในการย้ายข้อมูล���น้าจอ��นะนำ