หน้านี้จะอธิบายสาเหตุที่พบบ่อยซึ่งทำให้บริการที่ทำงานอยู่เบื้องหน้าทำงานไม่สำเร็จ และช่วยคุณระบุสาเหตุของปัญหา
เอกสารนี้จะกล่าวถึงปัญหาต่อไปนี้
ก่อนแก้ปัญหา
ตรวจสอบการเปลี่ยนแปลงล่าสุดในบริการที่ทำงานอยู่เบื้องหน้า
หากใช้บริการที่ทำงานอยู่เบื้องหน้าอย่างไม่เหมาะสม อาจส่งผลเสียต่อประสิทธิภาพของอุปกรณ์และระยะเวลาการใช้งานแบตเตอรี่ ด้วยเหตุนี้ แพลตฟอร์ม Android เวอร์ชันต่างๆ จึงมักทำการเปลี่ยนแปลงลักษณะการทำงานของบริการที่ทำงานอยู่เบื้องหน้าเพื่อจำกัดผลเสียเหล่านี้
หากพบปัญหาเกี่ยวกับบริการที่ทำงานอยู่เบื้องหน้า คุณควรตรวจสอบเอกสารประกอบเกี่ยวกับการเปลี่ยนแปลงบริการที่ทำงานอยู่เบื้องหน้า และดูว่ามีการเปลี่ยนแปลงล่าสุดที่อาจอธิบายปัญหาของคุณได้หรือไม่ คุณควรตรวจสอบการเปลี่ยนแปลงในสถานการณ์ต่อไปนี้เป็นพิเศษ
- โค้ดบริการที่ทำงานอยู่เบื้องหน้าที่เคยทำงานได้ก่อนหน้านี้ไม่ทำงานแล้ว
- คุณเพิ่งเริ่มทดสอบแพลตฟอร์มรุ่นใหม่ หรือคุณได้เปลี่ยนระดับ API ที่แอปกำหนดเป้าหมาย
นอกจากนี้ หากคุณกำลังทดสอบอุปกรณ์ในเวอร์ชันตัวอย่างสำหรับนักพัฒนาซอฟต์แวร์ของแพลตฟอร์ม โปรดตรวจสอบเอกสารประกอบของเวอร์ชันตัวอย่างสำหรับนักพัฒนาซอฟต์แวร์เวอร์ชันล่าสุด
ข้อผิดพลาดแอปพลิเคชันไม่ตอบสนอง (ANR)
ในบางกรณี แอปควรปิดบริการที่ทำงานอยู่เบื้องหน้า หากแอปไม่หยุดบริการ ระบบจะหยุดบริการและทำให้เกิดข้อผิดพลาดแอปพลิเคชันไม่ตอบสนอง (ANR)
บริการแบบสั้นทำงานนานเกินไปจนทำให้เกิด ANR
บริการที่ทำงานอยู่เบื้องหน้าซึ่งใช้ประเภทบริการสั้นต้องดำเนินการให้เสร็จอย่างรวดเร็วภายในเวลาประมาณ 3 นาที เมื่อหมดเวลา ระบบจะเรียกใช้เมธอด Service.onTimeout(int,int) ของบริการ บริการมีเวลา 2-3 วินาทีในการโทรหา stopSelf() หากบริการไม่หยุดทำงานเอง ระบบจะทริกเกอร์ข้อผิดพลาด "แอปพลิเคชันไม่ตอบสนอง"
วิเคราะห์:
หาก ANR เกิดจากบริการที่ทำงานอยู่เบื้องหน้าไม่หยุดทำงาน ระบบจะแสดงข้อยกเว้นภายใน คุณสามารถยืนยันได้ว่าปัญหานี้เกิดขึ้นจริงโดยการตรวจสอบรายงาน ANR หากเป็นกรณีนี้ รายงานจะมีข้อความต่อไปนี้
Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type FOREGROUND_SERVICE_TYPE_SHORT_SERVICE did not stop within its timeout:
[component name]"
วิธีแก้ไข
ตรวจสอบว่าบริการที่ทำงานอยู่เบื้องหน้าซึ่งมีเวลาจำกัดทั้งหมดทำงานเสร็จและเรียกใช้ stopForeground(int) ภายในเวลาที่ระบบจำกัดไว้
ให้ใช้ Service.onTimeout(int,int) ในบริการที่ทำงานอยู่เบื้องหน้า
ตรวจสอบว่าการติดตั้งใช้งานเมธอดดังกล่าวเรียกใช้ stopSelf() ทันที
ข้อยกเว้นสำหรับบริการที่ทำงานอยู่เบื้องหน้า
ส่วนนี้จะอธิบายปัญหาเกี่ยวกับบริการที่ทำงานอยู่เบื้องหน้าหลายประการที่อาจทำให้ระบบแสดงข้อยกเว้น หากแอปไม่ตรวจจับข้อยกเว้น ผู้ใช้จะเห็นกล่องโต้ตอบที่แจ้งว่าแอปหยุดทำงาน
ในบางกรณี ระบบจะแสดงข้อยกเว้นภายใน ในกรณีดังกล่าว คุณสามารถดูข้อยกเว้นได้โดยดูในสแต็กเทรซ และตรวจสอบ Logcat เพื่อดูข้อมูลข้อผิดพลาดโดยละเอียดเพิ่มเติม
ข้อยกเว้นภายใน: เกินระยะหมดเวลา
ระบบจะจำกัดระยะเวลาที่บริการที่ทำงานอยู่เบื้องหน้าสำหรับการซิงค์ข้อมูลและการประมวลผลสื่อจะทำงานได้ขณะที่แอปทำงานอยู่เบื้องหลัง หากบริการเกินขีดจำกัดดังกล่าว ระบบจะเรียกใช้เมธอด Service.onTimeout(int,int) ของบริการ บริการมีเวลา 2-3 วินาทีในการเรียกใช้ stopSelf() หากบริการไม่หยุดทำงานเอง ระบบจะสร้าง RemoteServiceException ภายในซึ่งทำให้แอปขัดข้อง
วิเคราะห์:
คุณสามารถดูว่าข้อยกเว้นคืออะไรได้โดยดูในสแต็กเทรซ และตรวจสอบ Logcat เพื่อดูข้อมูลข้อผิดพลาดโดยละเอียดเพิ่มเติม ในกรณีนี้ Logcat จะมีข้อความแสดงข้อผิดพลาดต่อไปนี้
Fatal Exception: android.app.RemoteServiceException: "A foreground service of
type [service type] did not stop within its timeout: [component name]"
วิธีแก้ไข
ตรวจสอบว่าบริการที่ทำงานอยู่เบื้องหน้าซึ่งมีเวลาจำกัดทั้งหมดทำงานเสร็จและเรียกใช้ stopForeground(int) ภายในขีดจำกัดเวลาของระบบ
ให้ใช้ Service.onTimeout(int,int) ในบริการที่ทำงานอยู่เบื้องหน้า
ตรวจสอบว่าการติดตั้งใช้งานเมธอดดังกล่าวเรียกใช้ stopSelf() ทันที
ข้อยกเว้นภายใน: ForegroundServiceDidNotStartInTimeException
เมื่อคุณเปิดใช้บริการโดยเรียกใช้ context.startForegroundService() บริการดังกล่าวจะมีเวลา 2-3 วินาทีในการโปรโมตตัวเองเป็นบริการที่ทำงานอยู่เบื้องหน้าโดยเรียกใช้ ServiceCompat.startForeground()
หากบริการไม่ดำเนินการดังกล่าว ระบบจะแสดงข้อผิดพลาดภายใน ForegroundServiceDidNotStartInTimeException
วิเคราะห์:
คุณสามารถดูว่าข้อยกเว้นคืออะไรได้โดยดูในสแต็กเทรซ และตรวจสอบ Logcat เพื่อดูข้อมูลข้อผิดพลาดโดยละเอียดเพิ่มเติม ในกรณีนี้ Logcat จะมีข้อความแสดงข้อผิดพลาดต่อไปนี้
android.app.RemoteServiceException$ForegroundServiceDidNotStartInTimeException:
Context.startForegroundService() did not then call Service.startForeground()
วิธีแก้ไข
ตรวจสอบว่าบริการที่ทำงานอยู่เบื้องหน้าที่สร้างขึ้นใหม่ทั้งหมดเรียกใช้ ServiceCompat.startForeground() ภายในไม่กี่วินาที
WorkManager:
คุณอาจเห็นข้อยกเว้นนี้กับ Worker WorkManager ที่เรียกใช้บริการที่ทำงานอยู่เบื้องหน้า (เรียก setForegound หรือ setForegroundAsync) เมื่อวงจรของ Worker ที่ทำงานอยู่เบื้องหน้า 2 รายการทับซ้อนกันเนื่องจาก Worker รายหนึ่งพยายามเริ่มบริการที่ทำงานอยู่เบื้องหน้าขณะที่บริการที่ทำงานอยู่เบื้องหน้าซึ่งทำงานอยู่ก่อนหน้านี้พยายามปิดตัวลง การขัดข้องนี้จะมาพร้อมกับบันทึกต่อไปนี้
Re-initializing SystemForegroundService after a request to shut-down
การแก้ไขข้อขัดข้องนี้เปิดตัวใน WorkManager เวอร์ชัน 2.10.5
หากแอปพบข้อยกเว้นนี้ ให้อัปเดต WorkManager เป็นเวอร์ชันล่าสุดและรายงานปัญหาที่ยังคงอยู่ไปยังIssue Trackerของ WorkManager
ForegroundServiceStartNotAllowedException
ข้อผิดพลาด:
ระบบจะแสดง ForegroundServiceStartNotAllowedException
สาเหตุ:
ซึ่งโดยปกติจะเกิดจากการที่แอปเปิดใช้บริการที่ทำงานอยู่เบื้องหน้าจากเบื้องหลังเมื่อไม่มีข้อยกเว้นที่ถูกต้อง
ตั้งแต่ Android 12 (ระดับ API 31) เป็นต้นไป แอปไม่ได้รับอนุญาตให้เริ่มบริการที่ทำงานอยู่เบื้องหน้าขณะที่แอปทำงานอยู่ในเบื้องหลัง ยกเว้นในบางกรณีที่ได้รับการยกเว้น
หากคุณพยายามเริ่มบริการที่ทำงานอยู่เบื้องหน้าจากเบื้องหลังและไม่เป็นไปตามข้อกำหนดของการยกเว้นข้อใดข้อหนึ่ง ระบบจะแสดง ForegroundServiceStartNotAllowedException นอกจากนี้ ระบบจะดำเนินการดังกล่าวหากคุณไม่มีคุณสมบัติตรงตามข้อกำหนดของการยกเว้น
เช่น แอปอาจมีปุ่มที่ผู้ใช้คลิกได้ ซึ่งจะทำให้แอปประมวลผลบางอย่างแล้วเปิดบริการที่ทำงานอยู่เบื้องหน้า ในกรณีนี้อาจมีความเสี่ยงที่ผู้ใช้อาจคลิกปุ่มแล้วทำให้แอปทำงานอยู่เบื้องหลังทันที จากนั้นแอปจะพยายามเปิดบริการจากเบื้องหลัง หากแอปไม่เป็นไปตามข้อยกเว้นที่ระบุไว้ ระบบจะแสดงข้อผิดพลาด ForegroundServiceStartNotAllowedException
นอกจากนี้ การยกเว้นบางรายการยังมีระยะเวลาที่จำกัด ตัวอย่างเช่น จะมีการยกเว้นสั้นๆ หากแอปของคุณเปิดบริการที่ทำงานอยู่เบื้องหน้าเพื่อตอบสนองต่อข้อความ FCM ที่มีความสำคัญสูง หากคุณไม่เปิดตัวบริการเร็วพอ คุณจะได้รับ ForegroundServiceStartNotAllowedException
บางครั้งการยกเว้นที่เฉพาะเจาะจงอาจเข้มงวดมากขึ้นเมื่อมีการเปิดตัว Android เวอร์ชันใหม่ หากคุณเปลี่ยนเวอร์ชัน Android ที่แอปกำหนดเป้าหมาย โปรดดูเอกสารประกอบเกี่ยวกับการเปลี่ยนแปลงบริการที่ทำงานอยู่เบื้องหน้า และยืนยันว่าแอปของคุณยังคงเป็นไปตามข้อยกเว้นที่ได้รับอนุญาตข้อใดข้อหนึ่ง
วิธีแก้ไข
เปลี่ยนเวิร์กโฟลว์ของแอปเพื่อไม่ให้ต้องเปิดบริการที่ทำงานอยู่เบื้องหน้าขณะที่แอปทำงานอยู่เบื้องหลัง หรือยืนยันว่าแอปของคุณเป็นไปตามข้อยกเว้นข้อใดข้อหนึ่ง
คุณสามารถใช้คอมโพเนนต์ที่รับรู้วงจรเพื่อจัดการวงจรของแอป เพื่อไม่ให้พยายามเปิดบริการที่ทำงานอยู่เบื้องหน้าจากเบื้องหลังโดยไม่ตั้งใจ
SecurityException
ข้อผิดพลาด:
ระบบจะแสดงข้อผิดพลาด SecurityException
สาเหตุ:
แอปของคุณพยายามเปิดบริการที่ทำงานอยู่เบื้องหน้าโดยไม่มีสิทธิ์ที่จำเป็น
- หากแอปกำหนดเป้าหมายเป็น Android 9 (ระดับ API 28) ขึ้นไป แอปต้องมีสิทธิ์
FOREGROUND_SERVICEเพื่อเปิดบริการที่ทำงานอยู่เบื้องหน้า - หากแอปกำหนดเป้าหมายเป็น Android 14 (ระดับ API 34) ขึ้นไป แอปต้องเป็นไปตามข้อกำหนดเบื้องต้นทั้งหมดสำหรับประเภทบริการที่ทำงานอยู่เบื้องหน้า ข้อกำหนดเบื้องต้นเหล่านี้มีรายละเอียดอยู่ในเอกสารประกอบเกี่ยวกับประเภทบริการที่ทำงานอยู่เบื้องหน้า โดยเฉพาะอย่างยิ่ง โปรดคำนึงถึงข้อกำหนดต่อไปนี้
- บริการที่ทำงานอยู่เบื้องหน้าหลายประเภทต้องใช้สิทธิ์รันไทม์ที่เฉพาะเจาะจง ตัวอย่างเช่น บริการที่ทำงานอยู่เบื้องหน้าสำหรับการรับส่งข้อความระยะไกลต้องมีสิทธิ์
FOREGROUND_SERVICE_REMOTE_MESSAGING
- บริการที่ทำงานอยู่เบื้องหน้าหลายประเภทต้องใช้สิทธิ์รันไทม์ที่เฉพาะเจาะจง ตัวอย่างเช่น บริการที่ทำงานอยู่เบื้องหน้าสำหรับการรับส่งข้อความระยะไกลต้องมีสิทธิ์
- ในหลายกรณี จะมีข้อจำกัดเพิ่มเติมขณะใช้งานเกี่ยวกับสิทธิ์ที่จำเป็นสำหรับบริการที่ทำงานอยู่เบื้องหน้าบางประเภท สิทธิ์เหล่านี้จะมอบให้แก่แอปขณะที่แอปทำงานอยู่เบื้องหน้าเท่านั้น (ยกเว้นในบางกรณี) ซึ่งหมายความว่าแม้ว่าแอปของคุณจะขอและได้รับสิทธิ์อย่างใดอย่างหนึ่งเหล่านี้แล้ว แต่หากแอปพยายามเปิดบริการที่ทำงานอยู่เบื้องหน้าขณะที่แอปอยู่ในเบื้องหลัง ระบบจะแสดง
SecurityExceptionแม้ว่าแอปจะได้รับการยกเว้นให้เริ่มบริการที่ทำงานอยู่เบื้องหน้าจากเบื้องหลังก็ตาม ดูข้อมูลเพิ่มเติมได้ที่ข้อจำกัดในการเริ่มบริการที่ทำงานอยู่เบื้องหน้าซึ่งต้องใช้สิทธิ์ขณะใช้งาน- คุณอาจได้รับ
SecurityExceptionหากขอสิทธิ์ที่จำเป็นแต่เริ่มบริการที่ทำงานอยู่เบื้องหน้าก่อนที่จะยืนยันว่าได้รับสิทธิ์ที่จำเป็นแล้ว
- คุณอาจได้รับ
วิธีแก้ไข
ก่อนเปิดบริการที่ทำงานอยู่เบื้องหน้า ให้ขอสิทธิ์บริการที่ทำงานอยู่เบื้องหน้าที่เหมาะสมทั้งหมด และยืนยันว่าคุณมีคุณสมบัติตรงตามข้อกำหนดเบื้องต้นอื่นๆ ทั้งหมดเกี่ยวกับรันไทม์