ผู้ใช้คาดหวังให้แอปโหลดได้อย่างรวดเร็วและตอบสนองได้ดี แอปที่มีเวลาเริ่มต้นช้า ไม่เป็นไปตามความคาดหวังนี้และอาจทำให้ผู้ใช้ผิดหวัง ประสบการณ์การใช้งานที่ไม่ดีเช่นนี้อาจทำให้ผู้ใช้ให้คะแนนแอปของคุณต่ำใน Play Store หรือแม้กระทั่งเลิกใช้แอปของคุณไปเลย
หน้านี้ให้ข้อมูลที่จะช่วยเพิ่มประสิทธิภาพเวลาเปิดแอป รวมถึงภาพรวมของกระบวนการเปิดแอปภายใน วิธีสร้างโปรไฟล์ ประสิทธิภาพการเริ่มต้น และปัญหาที่พบบ่อยเกี่ยวกับเวลาเริ่มต้นพร้อมเคล็ดลับวิธี แก้ไขปัญหา
ทำความเข้าใจสถานะการเริ่มต้นแอปต่างๆ
การเปิดแอปอาจเกิดขึ้นในสถานะใดสถานะหนึ่งต่อไปนี้ ได้แก่ Cold Start, Warm Start หรือ Hot Start แต่ละสถานะจะส่งผลต่อระยะเวลาที่แอปจะปรากฏต่อผู้ใช้ ใน Cold Start แอปจะเริ่มทำงานตั้งแต่ต้น ในรัฐอื่นๆ ระบบจะต้องนำแอปที่กำลังทำงานจากเบื้องหลังมาไว้ที่เบื้องหน้า
เราขอแนะนำให้คุณเพิ่มประสิทธิภาพโดยอิงตามสมมติฐานของ Cold Start เสมอ การทำเช่นนี้จะช่วยปรับปรุงประสิทธิภาพของการเริ่มต้นแบบอุ่นและแบบร้อนได้ด้วย
หากต้องการเพิ่มประสิทธิภาพแอปให้เริ่มต้นทำงานได้อย่างรวดเร็ว คุณควรทำความเข้าใจสิ่งที่เกิดขึ้นในระดับระบบและแอป รวมถึงวิธีที่ทั้ง 2 ระดับโต้ตอบกันในแต่ละสถานะ
เมตริกสำคัญ 2 รายการที่ใช้ในการพิจารณาการเริ่มต้นแอปคือเวลาที่ใช้ในการแสดงผลครั้งแรก (TTID) และเวลาที่ใช้ในการแสดงผลแบบเต็ม (TTFD) TTID คือเวลาที่ใช้ในการแสดงเฟรมแรก และ TTFD คือเวลาที่แอปใช้ในการตอบสนองอย่างสมบูรณ์ ทั้ง 2 อย่างมีความสำคัญเท่ากัน เนื่องจาก TTID จะช่วยให้ผู้ใช้ทราบว่าแอปกำลังโหลด และ TTFD คือเวลาที่ผู้ใช้ใช้งานแอปได้จริง หากระยะเวลาใดระยะเวลาหนึ่งนานเกินไป ผู้ใช้อาจออกจากแอปของคุณก่อนที่แอปจะโหลดเสร็จสมบูรณ์
Cold Start
Cold Start หมายถึงการเริ่มทำงานตั้งแต่ต้นของแอป ซึ่งหมายความว่าจนกว่าจะถึงจุดเริ่มต้นนี้ กระบวนการของระบบจะสร้างกระบวนการของแอป Cold Start เกิดขึ้น ในกรณีต่างๆ เช่น การเปิดแอปเป็นครั้งแรกนับตั้งแต่เปิดเครื่อง หรือนับตั้งแต่ระบบปิดแอป
การเริ่มต้นประเภทนี้ทำให้เกิดความท้าทายมากที่สุดในการลดเวลาในการเริ่มต้นใช้งาน เนื่องจากระบบและแอปต้องทำงานมากกว่าการเปิดในสถานะอื่นๆ
ในช่วงเริ่มต้นของ Cold Start ระบบจะมีงาน 3 อย่างต่อไปนี้
- โหลดและเปิดแอป
- แสดงหน้าต่างเริ่มต้นที่ว่างเปล่าสำหรับแอปทันทีหลังจากเปิดตัว
- สร้างกระบวนการของแอป
ทันทีที่ระบบสร้างกระบวนการของแอป กระบวนการของแอปจะมีหน้าที่รับผิดชอบ ในขั้นตอนถัดไป
- สร้างออบเจ็กต์แอป
- เปิดใช้ชุดข้อความหลัก
- สร้างกิจกรรมหลัก
- เริ่มต้น UI
- วาด UI บนหน้าจอ
เมื่อกระบวนการของแอปวาดภาพครั้งแรกเสร็จสมบูรณ์ กระบวนการของระบบจะสลับ หน้าต่างพื้นหลังที่แสดงออก แล้วแทนที่ด้วยกิจกรรมหลัก ในขั้นตอนนี้ ผู้ใช้จะเริ่มใช้แอปได้
ดูข้อมูลเพิ่มเติมเกี่ยวกับขั้นตอนเลย์เอาต์ใน Compose ได้ที่ ขั้นตอนของ Jetpack Compose
ปัญหาด้านประสิทธิภาพอาจเกิดขึ้นในระหว่างการสร้างแอปและการสร้าง กิจกรรมโฮสต์
การสร้างแอป
เมื่อแอปเปิดขึ้น หน้าต่างเริ่มต้นที่ว่างเปล่าจะยังคงอยู่บนหน้าจอจนกว่า ระบบจะวาดแอปเสร็จเป็นครั้งแรก ในตอนนี้ กระบวนการของระบบจะสลับหน้าต่างเริ่มต้นของแอปเพื่อให้ผู้ใช้โต้ตอบกับแอปได้
หากคุณแทนที่ Application.onCreate ในแอปของคุณเอง ระบบจะเรียกใช้เมธอด onCreate ในออบเจ็กต์แอป หลังจากนั้น แอปจะสร้างเทรดหลักหรือที่เรียกว่าเทรด UI และมอบหมายให้สร้างกิจกรรมโฮสต์ของแอป
จากจุดนี้ กระบวนการระดับระบบและแอปจะดำเนินการตามขั้นตอนวงจรชีวิตของแอป
การสร้างกิจกรรม
หลังจากกระบวนการของแอปสร้างกิจกรรมแล้ว กิจกรรมจะดำเนินการต่อไปนี้
- เริ่มต้นค่า
- เรียกตัวสร้าง
- เรียกใช้เมธอดเรียกกลับ เช่น
Activity.onCreateที่เหมาะสม กับสถานะวงจรปัจจุบันของกิจกรรม
โดยปกติแล้ว วิธี onCreate จะส่งผลต่อเวลาที่ใช้ในการโหลดมากที่สุด ในแอป Jetpack Compose ค่าใช้จ่ายของเมธอด onCreate มักมาจากการ
การคอมโพสครั้งแรก ซึ่งจะเกิดขึ้นเมื่อแอปเรียกใช้ setContent และ
เรียกใช้ Composable ระดับบนสุด ลำดับชั้น UI ที่ซับซ้อนหรือลึก หรือ
Composable ที่ทำการคำนวณหนักในเทรดหลัก อาจทำให้
เวลารวมนี้เพิ่มขึ้น
Warm Start
การเริ่มแอปแบบ Warm Start ครอบคลุมการดำเนินการบางส่วนที่เกิดขึ้นระหว่างการเริ่มแอปแบบ Cold Start ในขณะเดียวกัน ก็แสดงถึงค่าใช้จ่ายที่มากกว่าการเริ่มต้นแบบ Hot Start สถานะที่เป็นไปได้หลายอย่างถือเป็นการเริ่มต้นแบบวอร์ม เช่น สถานะต่อไปนี้
ผู้ใช้ออกจากแอปของคุณ แต่จากนั้นก็เปิดแอปอีกครั้ง กระบวนการอาจทำงานต่อไปได้ แต่แอปต้องสร้างกิจกรรมใหม่ตั้งแต่ต้นโดยใช้การเรียกไปยัง
onCreateระบบจะนำแอปออกจากหน่วยความจำ แล้วผู้ใช้จะเปิดแอปอีกครั้ง กระบวนการและกิจกรรมต้องรีสตาร์ท แต่ทาสก์จะได้รับประโยชน์บ้าง จากชุดสถานะอินสแตนซ์ที่บันทึกไว้ซึ่งส่งไปยัง
onCreate
Hot Start
การเริ่มแอปแบบ Hot Start มีค่าใช้จ่ายต่ำกว่าการเริ่มแอปแบบ Cold Start ในการเริ่มแบบ Hot Start ระบบจะนำกิจกรรมโฮสต์ของแอปไปไว้ที่เบื้องหน้า หาก UI ของแอปทั้งหมด ยังคงอยู่ในหน่วยความจำ แอปจะหลีกเลี่ยงการเริ่มต้นออบเจ็กต์ การเริ่มต้น UI และการแสดงผลซ้ำได้
อย่างไรก็ตาม หากมีการล้างข้อมูลในหน่วยความจำบางส่วนเพื่อตอบสนองต่อเหตุการณ์การลดหน่วยความจำ เช่น
onTrimMemory คุณจะต้องสร้างออบเจ็กต์เหล่านี้ขึ้นใหม่เพื่อตอบสนองต่อ
เหตุการณ์ Hot Start
Hot Start จะแสดงพฤติกรรมบนหน้าจอเหมือนกับสถานการณ์ Cold Start กระบวนการของระบบจะแสดงหน้าจอว่างเปล่าจนกว่าแอปจะแสดงผลกิจกรรมเสร็จสมบูรณ์
วิธีระบุการเริ่มต้นแอปใน Perfetto
หากต้องการแก้ไขข้อบกพร่องของปัญหาการเริ่มต้นแอป คุณควรพิจารณาว่ามีอะไรบ้าง ในระยะการเริ่มต้นแอป หากต้องการระบุทั้งระยะเริ่มต้นของแอปใน Perfetto ให้ทำตามขั้นตอนต่อไปนี้
ใน Perfetto ให้ค้นหาแถวที่มีเมตริกที่ได้มาจากการเริ่มต้นแอป Android หากไม่เห็น ให้ลองบันทึกการติดตามโดยใช้แอปการติดตามระบบในอุปกรณ์
รูปที่ 2 ชิ้นเมตริกการเริ่มต้นแอป Android ที่ได้มาจาก Perfetto คลิก Slice ที่เกี่ยวข้อง แล้วกด m เพื่อเลือก Slice วงเล็บจะปรากฏรอบๆ สไลซ์และระบุระยะเวลาที่ใช้ ระยะเวลาจะแสดงในแท็บการเลือกปัจจุบันด้วย
ปักหมุดแถวการเริ่มต้นแอป Android โดยคลิกไอคอนหมุดซึ่งจะ ปรากฏขึ้นเมื่อวางเคอร์เซอร์เหนือแถว
เลื่อนไปที่แถวที่มีแอปที่เป็นปัญหา แล้วคลิกเซลล์แรกเพื่อขยายแถว
ซูมเข้าที่เธรดหลัก ซึ่งมักจะอยู่ด้านบน โดยกด w (กด s, a, d เพื่อซูมออก เลื่อนไปทางซ้าย และเลื่อนไปทางขวา ตามลำดับ)
รูปที่ 3 Slice เมตริกการเริ่มต้นแอป Android ที่ได้มาจะอยู่ถัดจาก ชุดข้อความหลักของแอป การแบ่งเมตริกที่ได้มาช่วยให้คุณเห็นได้ง่ายขึ้นว่ามีอะไรบ้างที่รวมอยู่ในการเริ่มต้นแอป คุณจึงสามารถแก้ไขข้อบกพร่องต่อไปได้อย่างละเอียดมากขึ้น
เมื่อวิเคราะห์แอปพลิเคชัน Jetpack Compose คุณสามารถใช้การติดตามการคอมโพสเพื่อดูรายละเอียดแบบละเอียดเกี่ยวกับประสิทธิภาพของ UI
โปรดให้ความสนใจเป็นพิเศษกับส่วนการติดตามภายในเธรดหลักที่เริ่มต้นด้วย
Choreographer#doFrame มองหาชิ้นส่วน เช่น Compose:recompose
Compose:layout และ Compose:draw ซึ่งจะแสดงระยะเวลาที่แอปใช้ในการเขียน วัดผล และวาง รวมถึงวาดคอมโพเนนต์ที่เฉพาะเจาะจง
ใช้เมตริกเพื่อตรวจสอบและปรับปรุงการเริ่มต้น
หากต้องการวินิจฉัยประสิทธิภาพเวลาเริ่มต้นอย่างถูกต้อง คุณสามารถติดตามเมตริกที่แสดง ระยะเวลาที่แอปใช้ในการเริ่มต้น Android มีวิธีต่างๆ ในการแสดงให้คุณเห็นว่าแอปมีปัญหาและช่วยคุณวินิจฉัยปัญหา Android vitals สามารถ แจ้งเตือนคุณว่ามีปัญหาเกิดขึ้น และเครื่องมือวินิจฉัยจะช่วยคุณ วินิจฉัยปัญหาได้
ประโยชน์ของการใช้เมตริกสำหรับสตาร์ทอัพ
Android ใช้เมตริกเวลาที่ใช้ในการแสดงผลครั้งแรก (TTID) และเวลาที่ใช้ในการแสดงผลทั้งหมด (TTFD) เพื่อเพิ่มประสิทธิภาพการเริ่มต้นแอปแบบเย็นและแบบอุ่น Android Runtime (ART) ใช้ข้อมูลจากเมตริกเหล่านี้เพื่อคอมไพล์โค้ดล่วงหน้าอย่างมีประสิทธิภาพเพื่อเพิ่มประสิทธิภาพ การเริ่มต้นระบบในอนาคต
การเริ่มต้นที่เร็วขึ้นจะนำไปสู่การโต้ตอบของผู้ใช้กับแอปที่ยั่งยืนมากขึ้น ซึ่งจะช่วยลดกรณีที่ผู้ใช้ออกจากแอปก่อนเวลาอันควร รีสตาร์ทอินสแตนซ์ หรือไปยังแอปอื่น
Android Vitals
Android Vitals ช่วยปรับปรุงประสิทธิภาพของแอปได้โดยการแจ้งเตือนใน Play Console เมื่อเวลาเริ่มต้นของแอปนานเกินไป
Android Vitals ถือว่าเวลาเริ่มต้นต่อไปนี้ของแอปมากเกินไป
- Cold Startup ใช้เวลา 5 วินาทีขึ้นไป
- การเริ่มต้นอุ่นเครื่องใช้เวลา 2 วินาทีขึ้นไป
- Startup แบบHot ใช้เวลา 1.5 วินาทีขึ้นไป
Android Vitals ใช้เมตริกเวลาที่ใช้ในการแสดงผลครั้งแรก (TTID) ดูข้อมูลเกี่ยวกับวิธีที่ Google Play เก็บรวบรวมข้อมูล Android Vitals ได้ในเอกสารประกอบของ Play Console
เวลาที่ใช้ในการเริ่มแสดงผล
เวลาที่ใช้ในการเริ่มแสดงผล (TTID) คือระยะเวลาที่ใช้ในการแสดงเฟรมแรก
ของ UI ของแอป เมตริกนี้วัดระยะเวลาที่แอปใช้ในการสร้างเฟรมแรก ซึ่งรวมถึงการเริ่มต้นกระบวนการระหว่าง Cold Start การสร้างกิจกรรมระหว่าง Cold Start หรือ Warm Start และการแสดงเฟรมแรก การรักษา TTID ของแอปให้ต่ำจะช่วยปรับปรุงประสบการณ์ของผู้ใช้ด้วยการให้ผู้ใช้เห็นการเปิดตัวแอปอย่างรวดเร็ว
Android Framework จะรายงาน TTID โดยอัตโนมัติสำหรับทุกแอป
เมื่อเพิ่มประสิทธิภาพการเริ่มต้นแอป เราขอแนะนำให้ใช้ reportFullyDrawn เพื่อรับข้อมูลจนถึง TTFD
TTID วัดเป็นค่าเวลาที่แสดงเวลาที่ผ่านไปทั้งหมด ซึ่ง รวมถึงลําดับเหตุการณ์ต่อไปนี้
- เริ่มกระบวนการ
- กำลังเริ่มต้นออบเจ็กต์
- การสร้างและเริ่มต้นกิจกรรมของโฮสต์
- กำลังเริ่มต้น UI
- วาดแอปเป็นครั้งแรก
ดึงข้อมูล TTID
หากต้องการค้นหา TTID ให้ค้นหาในเครื่องมือบรรทัดคำสั่ง Logcat สำหรับบรรทัดเอาต์พุต
ที่มีค่าที่ชื่อว่า Displayed ค่านี้คือ TTID และมีลักษณะคล้ายกับตัวอย่างต่อไปนี้ ซึ่ง TTID คือ 3s534ms
ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms
หากต้องการค้นหา TTID ใน Android Studio ให้ปิดใช้ตัวกรองในมุมมอง Logcat จากเมนูตัวกรองแบบเลื่อนลง แล้วค้นหาเวลา Displayed ตามที่แสดงในรูปที่ 4
คุณต้องปิดใช้ตัวกรองเนื่องจากเซิร์ฟเวอร์ระบบเป็นผู้แสดงบันทึกนี้ ไม่ใช่แอป
เอง
Displayed
ใน Logcatเมตริก Displayed ในเอาต์พุต Logcat ไม่ได้บันทึก
ระยะเวลาจนกว่าจะโหลดและแสดงทรัพยากรทั้งหมด โดยจะละเว้น
ทรัพยากรที่ไม่ได้อ้างอิงในการคอมโพสเริ่มต้น (เช่น ข้อมูลหรือรูปภาพที่โหลดแบบไม่พร้อมกัน)
หรือทรัพยากรที่แอปสร้างขึ้นเป็น
ส่วนหนึ่งของการเริ่มต้นออบเจ็กต์ ระบบไม่รวมทรัพยากรเหล่านี้เนื่องจากการโหลดทรัพยากรเหล่านี้เป็นกระบวนการแบบอินไลน์และไม่ได้บล็อกการแสดงผลเริ่มต้นของแอป
ดูข้อมูลเพิ่มเติมเกี่ยวกับทรัพยากรได้ที่ทรัพยากรใน Compose
บางครั้งDisplayed ในเอาต์พุต Logcat จะมีฟิลด์เพิ่มเติม
สำหรับเวลาทั้งหมด ดังตัวอย่างต่อไปนี้
ActivityManager: Displayed com.android.myexample/.StartupTiming: +3s534ms (total +1m22s643ms)
ในกรณีนี้ การวัดครั้งแรกจะใช้กับกิจกรรมที่วาดเป็นครั้งแรกเท่านั้น ซึ่งโดยปกติแล้วจะเป็นกิจกรรมโฮสต์ การวัดเวลา total จะเริ่มที่
กระบวนการเริ่มต้นของแอป และอาจรวมถึงกิจกรรมอื่นที่เริ่มต้นก่อน
แต่ไม่ได้แสดงสิ่งใดบนหน้าจอ totalการวัดเวลาจะแสดง
เฉพาะเมื่อเวลาเริ่มต้นของกิจกรรมเดียวและเวลาเริ่มต้นทั้งหมด
แตกต่างกัน
เราขอแนะนำให้ใช้ Logcat ใน Android Studio แต่หากไม่ได้ใช้ Android
Studio คุณก็วัด TTID ได้โดยการเรียกใช้แอปด้วยคำสั่ง adb Shell
Activity Manager ตัวอย่าง
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 จะรวม TTID และเวลาที่แอปใช้ได้ การรักษา TTFD ของแอปให้ต่ำจะช่วยปรับปรุงประสบการณ์ของผู้ใช้ด้วยการให้ผู้ใช้โต้ตอบกับแอปได้อย่างรวดเร็ว
แม้ว่าระบบจะกำหนด TTID ได้เมื่อหน้าต่างโฮสต์แสดงเฟรมเริ่มต้น แต่ก็กำหนด TTFD โดยอัตโนมัติไม่ได้ เนื่องจากแอปมักจะโหลดเนื้อหาหลักแบบไม่พร้อมกัน ระบบจึงไม่ทราบว่าเมื่อใดที่ผู้ใช้จะสามารถใช้แอปได้อย่างเต็มที่ หากต้องการกำหนด TTFD แอปจะต้องส่งสัญญาณไปยังระบบเมื่อถึงสถานะที่วาดเสร็จสมบูรณ์
เรียกข้อมูล TTFD
หากต้องการค้นหา TTFD ให้ส่งสัญญาณสถานะที่วาดเสร็จสมบูรณ์โดยเรียกใช้เมธอด reportFullyDrawn ของ ComponentActivity เมธอด
reportFullyDrawn จะรายงานเมื่อแอปวาดเสร็จสมบูรณ์และอยู่ในสถานะที่ใช้งานได้
TTFD คือระยะเวลาที่ผ่านไปนับจากเวลาที่ระบบได้รับ Intent การเปิดแอป
จนถึงเวลาที่เรียกใช้ reportFullyDrawn หากคุณไม่เรียกใช้
reportFullyDrawn ระบบจะไม่รายงานค่า TTFD
หากต้องการวัด TTFD ให้เรียกใช้ reportFullyDrawn หลังจากวาด UI และ
ข้อมูลทั้งหมดเสร็จสมบูรณ์ อย่าเรียกใช้ reportFullyDrawn ก่อนที่หน้าต่างของกิจกรรมแรกจะวาดและแสดงเป็นครั้งแรกตามที่ระบบวัด เนื่องจากในกรณีนี้ระบบจะรายงานเวลาที่ระบบวัด กล่าวคือ หากคุณเรียกใช้
reportFullyDrawn ก่อนที่ระบบจะตรวจพบ TTID ระบบจะรายงานทั้ง TTID และ TTFD เป็นค่าเดียวกัน และค่านี้คือค่า TTID
เมื่อใช้ reportFullyDrawn Logcat จะแสดงเอาต์พุตดังตัวอย่างต่อไปนี้
ซึ่ง TTFD คือ 1 วินาที 54 มิลลิวินาที
system_process I/ActivityManager: Fully drawn {package}/.MainActivity: +1s54ms
เอาต์พุต Logcat บางครั้งจะมีเวลา total ตามที่อธิบายไว้ในเวลาจนถึง
การแสดงผลครั้งแรก
หากเวลาแสดงผลช้ากว่าที่ต้องการ ให้ลองระบุ จุดคอขวดในกระบวนการเริ่มต้น
คุณสามารถใช้ reportFullyDrawn เพื่อส่งสัญญาณสถานะที่วาดเสร็จสมบูรณ์ในกรณีพื้นฐาน
ที่คุณทราบว่าระบบแสดงผลจนเสร็จสมบูรณ์แล้ว อย่างไรก็ตาม ในกรณีที่
เธรดเบื้องหลังต้องทำงานเบื้องหลังให้เสร็จก่อนที่จะเข้าสู่สถานะที่วาดอย่างสมบูรณ์
คุณจะต้องหน่วงเวลา reportFullyDrawn เพื่อให้การวัด TTFD แม่นยำยิ่งขึ้น ดูวิธีเลื่อนเวลาreportFullyDrawnได้ที่ส่วนต่อไปนี้
ปรับปรุงความแม่นยำของเวลาเริ่มต้น
หากแอปของคุณใช้การโหลดแบบ Lazy Loading และจอแสดงผลเริ่มต้นไม่มีทรัพยากรทั้งหมด เช่น เมื่อแอปดึงข้อมูลรูปภาพจากเครือข่าย คุณอาจต้องเลื่อนการเรียก reportFullyDrawn จนกว่าแอปจะใช้งานได้ เพื่อให้คุณรวมการสร้างรายการเป็นส่วนหนึ่งของการกำหนดเวลาการเปรียบเทียบได้
ตัวอย่างเช่น หาก UI มีรายการแบบไดนามิก เช่น LazyColumn หรือ
LazyRow งานในเบื้องหลังอาจป้อนข้อมูลนี้หลังจากที่วาดรายการเป็นครั้งแรก และหลังจากที่ทำเครื่องหมาย UI ว่าวาดเสร็จสมบูรณ์แล้ว ในกรณีดังกล่าว ระบบจะไม่รวมการสร้างรายการในการเปรียบเทียบ
หากต้องการรวมการสร้างรายการเป็นส่วนหนึ่งของการกำหนดเวลาเกณฑ์เปรียบเทียบ ให้รับ
FullyDrawnReporter โดยใช้ fullyDrawnReporter แล้วเพิ่ม
เครื่องมือรายงานลงในโค้ดแอป ปล่อยรีพอร์ตเตอร์หลังจากที่งานในเบื้องหลัง
สร้างรายการเสร็จแล้ว
FullyDrawnReporter จะไม่เรียกใช้เมธอด reportFullyDrawn จนกว่าจะมีการเผยแพร่ผู้รายงานทั้งหมดที่เพิ่มเข้ามา
การเพิ่มเครื่องมือรายงานแต่ไม่เผยแพร่จนกว่ากระบวนการเบื้องหลังจะเสร็จสมบูรณ์จะช่วยให้มั่นใจได้ว่าข้อมูลเวลาเริ่มต้นจะมีเวลาในการป้อนข้อมูลรายการโดยไม่ต้องเปลี่ยนลักษณะการทำงานของแอปสำหรับผู้ใช้ reportFullyDrawn จะไม่เรียกใช้จนกว่างานทั้งหมดจะเสร็จสมบูรณ์ ไม่ว่าลำดับจะเป็นอย่างไรก็ตาม
หากแอปใช้ Jetpack Compose คุณสามารถใช้ API ต่อไปนี้เพื่อระบุสถานะ วาดเสร็จสมบูรณ์
ReportDrawn: แสดงว่า Composable พร้อมสำหรับการโต้ตอบทันทีReportDrawnWhen: รับค่าบูลีน เช่นlist.count > 0เพื่อระบุว่า Composable พร้อมสำหรับการโต้ตอบเมื่อใดReportDrawnAfter: ใช้เมธอดระงับที่เมื่อเสร็จสมบูรณ์แล้ว จะระบุว่า Composable พร้อมสำหรับการโต้ตอบ
ตัวอย่างต่อไปนี้แสดงวิธีเรียกใช้หลายงานในเบื้องหลังพร้อมกัน โดยแต่ละงานจะลงทะเบียนเครื่องมือรายงานของตัวเอง
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()
}
}
}
}
}
ระบุคอขวด
หากต้องการมองหาจุดคอขวด คุณสามารถใช้เครื่องมือสร้างโปรไฟล์ CPU ของ Android Studio ได้ ดูข้อมูลเพิ่มเติมได้ที่ตรวจสอบกิจกรรมของ CPU ด้วยเครื่องมือสร้างโปรไฟล์ CPU
นอกจากนี้ คุณยังได้รับข้อมูลเชิงลึกเกี่ยวกับปัญหาคอขวดที่อาจเกิดขึ้นผ่านการติดตามแบบอินไลน์
ภายในonCreateเมธอดของแอปและกิจกรรม ดูข้อมูลเกี่ยวกับการติดตามแบบอินไลน์ได้ในเอกสารประกอบสำหรับฟังก์ชัน Trace และภาพรวม
ของการติดตามระบบ
แก้ไขปัญหาที่พบบ่อย
ส่วนนี้จะกล่าวถึงปัญหาหลายอย่างที่มักส่งผลต่อประสิทธิภาพการเริ่มต้นแอป ปัญหาเหล่านี้เกี่ยวข้องกับการเริ่มต้นออบเจ็กต์แอปและกิจกรรม รวมถึงการโหลดหน้าจอเป็นหลัก
การเริ่มต้นแอปที่ใช้ทรัพยากรมาก
ประสิทธิภาพการเปิดตัวอาจลดลงเมื่อโค้ดของคุณลบล้างออบเจ็กต์ Application
และเรียกใช้งานหนักหรือตรรกะที่ซับซ้อนเมื่อเริ่มต้นออบเจ็กต์นั้น แอปอาจเสียเวลาในระหว่างการเริ่มต้นหากคลาสย่อย Application ทำการเริ่มต้นที่ไม่จำเป็นต้องทำในตอนนี้
การเริ่มต้นบางอย่างอาจไม่จำเป็นเลย เช่น เมื่อเริ่มต้น ข้อมูลสถานะสำหรับกิจกรรมหลักเมื่อแอปเริ่มต้นจริง เพื่อตอบสนองต่อ Intent เมื่อมี Intent แอปจะใช้เฉพาะชุดย่อย ของข้อมูลสถานะที่เริ่มต้นไว้ก่อนหน้านี้
ความท้าทายอื่นๆ ระหว่างการเริ่มต้นแอป ได้แก่ เหตุการณ์ระบบจัดการหน่วยความจำที่ไม่ใช้แล้วที่มีผลกระทบหรือมีจำนวนมาก หรือ I/O ของดิสก์ที่เกิดขึ้นพร้อมกันกับการเริ่มต้น ซึ่งบล็อกกระบวนการเริ่มต้นเพิ่มเติม ระบบจัดการหน่วยความจำที่ไม่ใช้แล้วเป็นสิ่งที่ต้องพิจารณาเป็นพิเศษเมื่อใช้รันไทม์ Dalvik ส่วน Android Runtime (ART) จะจัดการหน่วยความจำที่ไม่ใช้แล้วพร้อมกันเพื่อลดผลกระทบของการดำเนินการดังกล่าว
วินิจฉัยปัญหา
คุณสามารถใช้การติดตามเมธอดหรือการติดตามในบรรทัดเพื่อพยายามวินิจฉัยปัญหาได้
การติดตามเมธอด
การเรียกใช้เครื่องมือสร้างโปรไฟล์ CPU แสดงให้เห็นว่าเมธอด callApplicationOnCreate จะเรียกใช้เมธอด com.example.customApplication.onCreate ในที่สุด หาก
เครื่องมือแสดงว่าวิธีการเหล่านี้ใช้เวลานานในการดำเนินการให้เสร็จสมบูรณ์
ให้ตรวจสอบเพิ่มเติมเพื่อดูว่ามีงานใดเกิดขึ้นที่นั่น
การติดตามในบรรทัด
ใช้การติดตามแบบอินไลน์เพื่อตรวจสอบสาเหตุที่น่าจะเป็น ซึ่งรวมถึงสิ่งต่อไปนี้
- ฟังก์ชัน
onCreateเริ่มต้นของแอป - ออบเจ็กต์ Singleton ส่วนกลางที่แอปของคุณเริ่มต้น
- การอ่าน/เขียนดิสก์ การยกเลิกการซีเรียลไลซ์ หรือลูปที่แน่นหนาที่อาจเกิดขึ้นระหว่าง คอขวด
วิธีแก้ปัญหา
ไม่ว่าปัญหาจะเกิดจากการเริ่มต้นที่ไม่จำเป็นหรือ I/O ของดิสก์ วิธีแก้ปัญหาคือการเริ่มต้นแบบเลซี่ กล่าวคือ ให้เริ่มต้นออบเจ็กต์เฉพาะที่จำเป็นต้องใช้ทันทีเท่านั้น แทนที่จะสร้างออบเจ็กต์แบบคงที่ส่วนกลาง ให้เปลี่ยนไปใช้รูปแบบ Singleton ซึ่งแอปจะเริ่มต้นออบเจ็กต์เฉพาะครั้งแรกที่ต้องการใช้
นอกจากนี้ ให้พิจารณาใช้เฟรมเวิร์กการแทรกทรัพยากร Dependency เช่น Hilt ที่สร้างออบเจ็กต์และทรัพยากร Dependency เมื่อมีการแทรกเป็นครั้งแรก
หากแอปใช้ Content Provider เพื่อเริ่มต้นคอมโพเนนต์ของแอปเมื่อเริ่มต้น ให้ลองใช้ไลบรารีการเริ่มต้นแอปแทน
การเริ่มต้นกิจกรรมที่มีการใช้งานสูง
การสร้างกิจกรรมมักต้องใช้เวลาในการทำงานที่มีค่าใช้จ่ายสูง บ่อยครั้งที่ มีโอกาสในการเพิ่มประสิทธิภาพงานนี้เพื่อให้ได้การปรับปรุงประสิทธิภาพ ปัญหาทั่วไปดังกล่าว ได้แก่
- การเริ่มต้น UI ขนาดใหญ่หรือซับซ้อน
- การเริ่มต้นที่ซับซ้อนใน Composable
- การบล็อกการวาดหน้าจอในดิสก์หรือ I/O ของเครือข่าย
- การโหลดและถอดรหัสบิตแมป
- แรสเตอร์ออบเจ็กต์
VectorDrawable - การเริ่มต้นระบบย่อยอื่นๆ ของกิจกรรมโฮสต์ของแอป
วินิจฉัยปัญหา
ในกรณีนี้ การติดตามเมธอดและการติดตามแบบอินไลน์ก็มีประโยชน์เช่นกัน
การติดตามเมธอด
เมื่อใช้เครื่องมือสร้างโปรไฟล์ CPU ให้สังเกตApplication
ตัวสร้างคลาสย่อยและเมธอด com.example.customApplication.onCreate ของแอป
หากเครื่องมือแสดงว่าวิธีการเหล่านี้ใช้เวลานานในการดำเนินการให้เสร็จสมบูรณ์ ให้สำรวจเพิ่มเติมเพื่อดูว่ามีการทำงานใดเกิดขึ้น
การติดตามในบรรทัด
ใช้การติดตามแบบอินไลน์เพื่อตรวจสอบสาเหตุที่น่าจะเป็น ซึ่งรวมถึงสิ่งต่อไปนี้
- ฟังก์ชัน
onCreateเริ่มต้นของแอป - ออบเจ็กต์ Singleton ทั่วโลกที่เริ่มต้น
- การอ่าน/เขียนดิสก์ การยกเลิกการซีเรียลไลซ์ หรือลูปที่แน่นหนาที่อาจเกิดขึ้นระหว่าง คอขวด
วิธีแก้ปัญหา
แม้ว่าอาจมีคอขวดหลายจุด แต่ปัญหาที่พบบ่อย 2 ประการและวิธีแก้ไขมีดังนี้
- ยิ่งลำดับชั้น UI มีขนาดใหญ่มากเท่าไร แอปก็จะใช้เวลาในการเริ่มต้นนานขึ้นเท่านั้น
โปรดพิจารณาขั้นตอนต่อไปนี้เมื่อแก้ไขปัญหานี้
- ลดลำดับชั้น UI โดยลด Composable ที่ซ้ำซ้อนหรือซ้อนกัน
- หลีกเลี่ยงการจัดวางและจัดวางใหม่โดยไม่จำเป็นระหว่างการเปิดตัว
- เลื่อนการสร้าง UI ที่ไม่สำคัญ
- การเริ่มต้นทรัพยากรทั้งหมดในเทรดหลักอาจทำให้การเริ่มต้นระบบช้าลงด้วย
คุณแก้ไขปัญหานี้ได้โดยทำดังนี้
- ย้ายการเริ่มต้นทรัพยากรทั้งหมดเพื่อให้แอปดำเนินการอย่างไม่เร่งรีบใน เธรดอื่นได้
- โหลดและแสดง UI ด้วยข้อมูลตัวยึดตำแหน่งก่อน แล้วจึงอัปเดต พร็อพเพอร์ตี้ภาพที่ขึ้นอยู่กับบิตแมปและทรัพยากรอื่นๆ ในภายหลัง
ดูข้อมูลเพิ่มเติมเกี่ยวกับการจัดองค์ประกอบใหม่ได้ที่การจัดองค์ประกอบใหม่และ รับจำนวนการจัดองค์ประกอบใหม่
หน้าจอแนะนำที่กำหนดเอง
คุณอาจเห็นเวลาเพิ่มเติมที่เพิ่มเข้ามาในระหว่างการเริ่มต้นระบบหากก่อนหน้านี้คุณใช้วิธีใดวิธีหนึ่งต่อไปนี้เพื่อใช้หน้าจอแนะนําที่กําหนดเองใน Android 11 (API ระดับ 30) หรือก่อนหน้า
- ใช้แอตทริบิวต์ธีม
windowDisablePreviewเพื่อปิดหน้าจอว่างเริ่มต้นที่ระบบวาดขึ้นระหว่างการเปิดตัว - การใช้
Activityโดยเฉพาะ
ตั้งแต่ Android 12 เป็นต้นไป คุณจะต้องย้ายข้อมูลไปยัง SplashScreen API
API นี้ช่วยให้เวลาเริ่มต้นเร็วขึ้นและให้คุณปรับแต่งหน้าจอแนะนำได้ด้วยวิธีต่อไปนี้
- ตั้งค่าธีมเพื่อเปลี่ยนลักษณะที่ปรากฏของหน้าจอเริ่มต้น
- ควบคุมระยะเวลาการแสดงหน้าจอเริ่มต้นด้วย
windowSplashScreenAnimationDuration - ปรับแต่งภาพเคลื่อนไหวของหน้าจอเริ่มต้น และจัดการภาพเคลื่อนไหวสำหรับการปิดหน้าจอเริ่มต้นอย่างราบรื่น
นอกจากนี้ ไลบรารีความเข้ากันได้ยังย้อนกลับ SplashScreen API เพื่อเปิดใช้
ความเข้ากันได้แบบย้อนหลัง และสร้างรูปลักษณ์และความรู้สึกที่สอดคล้องกันสําหรับการแสดง
หน้าจอ Splash ใน Android ทุกเวอร์ชัน
ดูรายละเอียดได้ที่คำแนะนำในการย้ายข้อมูลหน้าจอเริ่มต้น
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- การแสดงผลช้า
- บันทึกเมตริก Macrobenchmark
- สร้างโปรไฟล์พื้นฐาน{:#creating-profile-rules}