พัฒนาประสบการณ์การนอนหลับด้วย Health Connect

หากต้องการสร้างประสบการณ์การติดตามการนอนหลับในแอป คุณสามารถใช้ Health Connect เพื่อทำสิ่งต่างๆ เช่น

  • เขียนข้อมูลเซสชันการนอนหลับ
  • เขียนข้อมูลระยะการนอนหลับ
  • เขียนข้อมูลการนอนหลับ เช่น อัตราการเต้นของหัวใจ ความอิ่มตัวของออกซิเจน และอัตราการหายใจ
  • อ่านข้อมูลการนอนหลับจากแอปอื่นๆ

คู่มือนี้อธิบายวิธีสร้างฟีเจอร์การนอนหลับเหล่านี้ โดยครอบคลุมประเภทข้อมูล การดำเนินการในเบื้องหลัง สิทธิ์ เวิร์กโฟลว์ที่แนะนำ และแนวทางปฏิบัติแนะนำ

ภาพรวม: การสร้างเครื่องมือติดตามการนอนหลับที่ครอบคลุม

คุณสร้างประสบการณ์การติดตามการนอนหลับที่ครอบคลุมได้โดยใช้ Health Connect โดยทำตามขั้นตอนหลักต่อไปนี้

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

เวิร์กโฟลว์นี้ช่วยให้ทำงานร่วมกับแอป Health Connect อื่นๆ ได้และยืนยันการเข้าถึงข้อมูลที่ผู้ใช้ควบคุม

ก่อนเริ่มต้น

ก่อนที่จะใช้ฟีเจอร์การนอนหลับ ให้ทำดังนี้

หัวข้อสำคัญ

Health Connect แสดงข้อมูลการนอนหลับโดยใช้คอมโพเนนต์หลัก 2-3 รายการ A SleepSessionRecord ทำหน้าที่เป็นบันทึกส่วนกลางสำหรับการนอนหลับ ซึ่งมีรายละเอียด เช่น เวลาเริ่มต้นหรือสิ้นสุด และระยะการนอนหลับ ในระหว่างเซสชัน ระบบจะบันทึกข้อมูลประเภทต่างๆ เช่น HeartRateRecord หรือ OxygenSaturationRecord

เซสชันการนอนหลับ

ข้อมูลการนอนหลับแสดงโดย SleepSessionRecord แต่ละระเบียนจะจัดเก็บข้อมูลต่อไปนี้

  • startTime
  • endTime
  • stages: รายการSleepSessionRecord.Stageซึ่งรวมถึงการหลับลึก หลับตื้น REM และการตื่น
  • ข้อมูลเมตาของเซสชันที่ไม่บังคับ (ชื่อ หมายเหตุ)

แอปอาจเขียนข้อมูลหลายประเภทที่เชื่อมโยงกับเซสชัน

ประเภทข้อมูล

ประเภทข้อมูลทั่วไปที่บันทึกในระหว่างเซสชันการนอนหลับ ได้แก่

  • SleepSessionRecord: บันทึกระยะเวลาและระยะการนอนหลับ รวมถึง การหลับลึก หลับตื้น ช่วง REM และการตื่นนอน
  • HeartRateRecord: บันทึกอัตราการเต้นของหัวใจขณะหลับ
  • OxygenSaturationRecord: บันทึกความอิ่มตัวของออกซิเจน (SpO2) ขณะ นอนหลับ
  • RespiratoryRateRecord: บันทึกอัตราการหายใจขณะนอนหลับ

ระบบจะจัดเก็บข้อมูลแต่ละประเภทเป็นระเบียนแยกกัน

ข้อควรพิจารณาในการพัฒนา

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

การดำเนินการเมื่ออยู่เบื้องหลัง

โดยปกติแล้วแอปติดตามการนอนหลับจะทำงานตลอดทั้งคืนขณะปิดหน้าจอ ในสถานะนี้ คุณควรใช้สิ่งต่อไปนี้

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

รักษาความต่อเนื่องโดยคง ID เซสชันให้สอดคล้องกันในการเขียนทั้งหมด

สิทธิ์

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

การเข้าถึงการนอนหลับได้รับการคุ้มครองโดยสิทธิ์ต่อไปนี้

  • android.permission.health.READ_SLEEP
  • android.permission.health.WRITE_SLEEP

หากต้องการเพิ่มความสามารถในการติดตามการนอนหลับลงในแอป ให้เริ่มด้วยการขอสิทธิ์สำหรับSleepSessionประเภทข้อมูล

สิทธิ์ที่คุณต้องประกาศเพื่อให้เขียน sleep ได้มีดังนี้

<application>
  <uses-permission
android:name="android.permission.health.WRITE_SLEEP" />
...
</application>

หากต้องการอ่านข้อมูลการนอนหลับ คุณต้องขอสิทธิ์ต่อไปนี้

<application>
  <uses-permission
android:name="android.permission.health.READ_SLEEP" />
...
</application>

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

หลังจากสร้างอินสแตนซ์ไคลเอ็นต์แล้ว แอปของคุณต้องขอสิทธิ์จากผู้ใช้ ผู้ใช้ต้องได้รับอนุญาตให้ให้สิทธิ์หรือปฏิเสธสิทธิ์ได้ทุกเมื่อ

โดยให้สร้างชุดสิทธิ์สำหรับประเภทข้อมูลที่จำเป็น ตรวจสอบว่าได้ประกาศสิทธิ์ในชุดไว้ในไฟล์ Manifest ของ Android ก่อน

// Create a set of permissions for required data types
val PERMISSIONS =
    setOf(
  HealthPermission.getReadPermission(SleepSessionRecord::class),
  HealthPermission.getWritePermission(SleepSessionRecord::class),
  HealthPermission.getReadPermission(HeartRateRecord::class),
  HealthPermission.getWritePermission(HeartRateRecord::class),
  HealthPermission.getReadPermission(OxygenSaturationRecord::class),
  HealthPermission.getWritePermission(OxygenSaturationRecord::class),
  HealthPermission.getReadPermission(RespiratoryRateRecord::class),
  HealthPermission.getWritePermission(RespiratoryRateRecord::class)
)

ใช้ getGrantedPermissions เพื่อดูว่าแอปของคุณได้รับสิทธิ์ที่จำเป็นแล้วหรือไม่ หากไม่มี ให้ใช้ createRequestPermissionResultContract เพื่อขอสิทธิ์เหล่านั้น ซึ่งจะแสดงหน้าจอขอสิทธิ์ของ Health Connect

// Create the permissions launcher
val requestPermissionActivityContract = PermissionController.createRequestPermissionResultContract()

val requestPermissions = registerForActivityResult(requestPermissionActivityContract) { granted ->
  if (granted.containsAll(PERMISSIONS)) {
    // Permissions successfully granted
  } else {
    // Lack of required permissions
  }
}

suspend fun checkPermissionsAndRun(healthConnectClient: HealthConnectClient) {
  val granted = healthConnectClient.permissionController.getGrantedPermissions()
  if (granted.containsAll(PERMISSIONS)) {
    // Permissions already granted; proceed with inserting or reading data
  } else {
    requestPermissions.launch(PERMISSIONS)
  }
}

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

ใช้เซสชันการนอนหลับ

ส่วนนี้อธิบายเวิร์กโฟลว์ที่แนะนำสำหรับการบันทึกข้อมูลการนอนหลับ

หากต้องการจัดประเภทข้อมูล เช่น HeartRateRecord หรือ OxygenSaturationRecord ให้สอดคล้องกับ เซสชันการนอนหลับ ให้บันทึกข้อมูลดังกล่าวพร้อมการประทับเวลาที่อยู่ระหว่าง startTime และ endTime ของเซสชัน Health Connect ไม่ได้ใช้ตัวระบุเซสชันเพื่อ ลิงก์เซสชันการนอนหลับกับข้อมูลแบบละเอียด แต่การเชื่อมโยงจะเกิดขึ้นโดยนัยผ่าน ช่วงเวลาที่ทับซ้อนกัน เมื่ออ่านข้อมูลการนอนหลับ คุณสามารถใช้ช่วงเวลาของเซสชัน เพื่อค้นหาประเภทข้อมูลที่เชื่อมโยงได้ ดังที่แสดงใน การอ่านข้อมูลการนอนหลับ

เขียนเซสชัน

แม้ว่าระบบจะบันทึกข้อมูลแบบละเอียด เช่น อัตราการเต้นของหัวใจ ตลอดเซสชันการนอนหลับได้ แต่ต้องเขียนข้อมูลSleepSessionRecordลงใน Health Connect เพียงครั้งเดียวเมื่อเซสชันสิ้นสุดลงแล้ว เช่น เมื่อผู้ใช้ตื่น บันทึกต้องมี เซสชัน startTime, endTime และรายการออบเจ็กต์ SleepSessionRecord.Stage ที่บันทึกไว้ระหว่างเซสชัน เนื่องจาก SleepSessionRecord กำหนดให้ endTime ต้องอยู่หลัง startTime

วิธีเขียนข้อมูลเซสชันการนอนหลับ

  1. สร้างรหัสบันทึกลูกค้าที่ไม่ซ้ำกัน
  2. เมื่อผู้ใช้ตื่นขึ้นหรือหยุดการติดตามการนอนหลับ ให้รวบรวมSleepSessionRecordและสร้าง SleepSessionRecord
  3. แทรกระเบียนโดยใช้ insertRecords

ตัวอย่าง

val clientRecordId = UUID.randomUUID().toString()
val sessionStartTime = LocalDateTime.of(2023, 10, 30, 22, 0).toInstant(ZoneOffset.UTC)
val sessionEndTime = LocalDateTime.of(2023, 10, 31, 7, 0).toInstant(ZoneOffset.UTC)

val stages = mutableListOf<SleepSessionRecord.Stage>()
// Add recorded stages, for example:
stages.add(SleepSessionRecord.Stage(
    startTime = sessionStartTime.plusSeconds(3600),
    endTime = sessionStartTime.plusSeconds(7200),
    stage = SleepSessionRecord.STAGE_TYPE_LIGHT)
)
stages.add(SleepSessionRecord.Stage(
    startTime = sessionStartTime.plusSeconds(7200),
    endTime = sessionStartTime.plusSeconds(10800),
    stage = SleepSessionRecord.STAGE_TYPE_DEEP)
)
// ... other stages

val session = SleepSessionRecord(
    startTime = sessionStartTime,
    startZoneOffset = ZoneOffset.UTC,
    endTime = sessionEndTime,
    endZoneOffset = ZoneOffset.UTC,
    stages = stages,
    metadata = Metadata(clientRecordId = clientRecordId)
)

healthConnectClient.insertRecords(listOf(session))

การอ่านข้อมูลการนอนหลับ

แอปสามารถอ่านเซสชันการนอนหลับและข้อมูลที่เกี่ยวข้องเพื่อสรุปกิจกรรม ให้ข้อมูลเชิงลึกด้านสุขภาพ หรือซิงค์ข้อมูลกับเซิร์ฟเวอร์ภายนอก เช่น คุณสามารถอ่าน SleepSessionRecord แล้วค้นหา HeartRateRecord ที่เกิดขึ้นในช่วงเวลาเดียวกันนั้น

เซสชันการอ่านที่มีข้อมูลที่เชื่อมโยง

คุณอ่านเซสชันการนอนหลับได้โดยใช้ ReadRecordsRequest ที่มี SleepSessionRecord เป็นประเภทบันทึก ซึ่งกรองตามช่วงเวลา หากต้องการอ่านข้อมูลที่เชื่อมโยงสำหรับเซสชันหนึ่งๆ ให้ส่งคำขอที่ 2 สำหรับประเภทข้อมูลที่เลือก เช่น HeartRateRecord—กรองตาม startTime และ endTime ของเซสชันการนอนหลับ

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

suspend fun readSleepSessionsWithAssociatedData(
    healthConnectClient: HealthConnectClient,
    startTime: Instant,
    endTime: Instant
) {
    val response = healthConnectClient.readRecords(
        ReadRecordsRequest(
            recordType = SleepSessionRecord::class,
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
        )
    )

    for (sleepRecord in response.records) {
        // Process each session
        val stages = sleepRecord.stages
        val notes = sleepRecord.notes

        // To read specific granular data (like heart rate) that occurred during
        // this session, use the session's startTime and endTime to filter
        // the request for that data type.
        val hrResponse = healthConnectClient.readRecords(
            ReadRecordsRequest(
                recordType = HeartRateRecord::class,
                timeRangeFilter = TimeRangeFilter.between(
                    sleepRecord.startTime,
                    sleepRecord.endTime
                )
            )
        )
        for (heartRateRecord in hrResponse.records) {
            for (sample in heartRateRecord.samples) {
                val bpm = sample.beatsPerMinute
            }
        }
    }
}

แนวทางปฏิบัติแนะนำ

โปรดทำตามหลักเกณฑ์ต่อไปนี้เพื่อปรับปรุงความน่าเชื่อถือของข้อมูลและประสบการณ์ของผู้ใช้

  • เขียนบ่อยๆ ระหว่างการติดตามที่ใช้งานอยู่: สำหรับการติดตามที่ใช้งานอยู่ ให้เขียนข้อมูลเมื่อพร้อมใช้งานหรือที่ช่วงเวลาสูงสุด 15 นาที
  • ใช้ WorkManager สำหรับการซิงค์ในเบื้องหลัง: ใช้ WorkManager สำหรับการเขียนที่เลื่อนออกไป ตั้งช่วงเวลา 15 นาทีเพื่อสร้างสมดุลระหว่างข้อมูลแบบเรียลไทม์และประสิทธิภาพแบตเตอรี่
  • คำขอเขียนแบบกลุ่ม: อย่าเขียนเหตุการณ์เซ็นเซอร์แต่ละรายการแยกกัน แบ่งคำขอออกเป็นส่วนๆ Health Connect จัดการบันทึกได้สูงสุด 1,000 รายการต่อคำขอเขียน
  • รักษารหัสเซสชันให้คงที่และไม่ซ้ำกัน: ใช้ตัวระบุที่สอดคล้องกันสำหรับเซสชัน หากมีการแก้ไขหรืออัปเดตเซสชัน การใช้รหัสเดียวกันจะช่วยป้องกันไม่ให้ระบบถือว่าเป็นเซสชันใหม่ที่แยกต่างหาก
  • ใช้การจัดกลุ่มสำหรับประเภทข้อมูล: หากต้องการลดค่าใช้จ่ายอินพุต/เอาต์พุตและรักษาอายุการใช้งานแบตเตอรี่ ให้จัดกลุ่มจุดข้อมูลเป็นinsertRecordsการเรียกใช้ครั้งเดียวแทนที่จะเขียนแต่ละจุดแยกกัน
  • หลีกเลี่ยงการเขียนข้อมูลที่ซ้ำกัน: ใช้ Client ID: เมื่อสร้างบันทึก ให้ตั้งค่า metadata.clientRecordId Health Connect ใช้ข้อมูลนี้เพื่อระบุบันทึกที่ไม่ซ้ำกัน หากคุณพยายามเขียนบันทึกที่มี clientRecordId อยู่แล้ว Health Connect จะไม่สนใจรายการที่ซ้ำกันหรืออัปเดตบันทึกที่มีอยู่แทนที่จะสร้างรายการใหม่ การตั้งค่า metadata.clientRecordId เป็นวิธีที่มีประสิทธิภาพที่สุดในการป้องกันรายการที่ซ้ำกันระหว่างการลองซิงค์อีกครั้งหรือการติดตั้งแอปใหม่
    val record = StepsRecord(
        count = 100,
        startTime = startTime,
        endTime = endTime,
        startZoneOffset = ZoneOffset.UTC,
        endZoneOffset = ZoneOffset.UTC,
        metadata = Metadata(
            // Use a unique ID from your own database
            clientRecordId = "daily_steps_2023_10_27_user_123"
        )
    )
  • ตรวจสอบข้อมูลที่มีอยู่: ก่อนซิงค์ ให้ค้นหาระยะเวลาเพื่อดูว่ามีบันทึกจากแอปอยู่แล้วหรือไม่
  • ตรวจสอบว่าการประทับเวลาไม่ทับซ้อนกัน: ตรวจสอบว่าเซสชันใหม่จะไม่เริ่มก่อนที่เซสชันก่อนหน้าจะสิ้นสุด เซสชันที่ทับซ้อนกันอาจทำให้เกิดข้อขัดแย้งในแดชบอร์ดฟิตเนสและการคำนวณข้อมูลสรุป
  • ระบุเหตุผลที่ชัดเจนสำหรับสิทธิ์: ใช้โฟลว์ Permission.createIntent เพื่ออธิบายเหตุผลที่แอปของคุณต้องเข้าถึงข้อมูลสุขภาพ เช่น "เพื่อตรวจสอบแนวโน้มความดันโลหิตและให้ข้อมูลเชิงลึก"
  • ทดสอบเซสชันที่ทำงานเป็นเวลานาน: ตรวจสอบการใช้แบตเตอรี่ระหว่างเซสชันที่ใช้เวลาหลายชั่วโมงเพื่อยืนยันว่าช่วงการจัดกลุ่มและการใช้เซ็นเซอร์ไม่ได้ทำให้แบตเตอรี่ของอุปกรณ์หมดเร็ว
  • จัดแนวการประทับเวลาให้ตรงกับอัตราเซ็นเซอร์: จับคู่การประทับเวลาของบันทึกกับความถี่จริงของเซ็นเซอร์เพื่อรักษาความเที่ยงตรงของข้อมูล

การทดสอบ

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

เครื่องมือยืนยัน

  • กล่องเครื่องมือ Health Connect: ใช้แอปคู่หูนี้เพื่อตรวจสอบระเบียนด้วยตนเอง ลบข้อมูลทดสอบ และจำลองการเปลี่ยนแปลงในฐานข้อมูล ซึ่งเป็น วิธีที่ดีที่สุดในการยืนยันว่าระบบจัดเก็บระเบียนของคุณอย่างถูกต้อง
  • การทำ Unit Test ด้วย FakeHealthConnectClient: ใช้ไลบรารีการทดสอบ เพื่อยืนยันวิธีที่แอปจัดการกรณีขอบ เช่น การเพิกถอนสิทธิ์หรือข้อยกเว้น API โดยไม่ต้องใช้อุปกรณ์จริง

รายการตรวจสอบคุณภาพ

สถาปัตยกรรมทั่วไป

โดยปกติการติดตั้งใช้งานการติดตามการนอนหลับจะมีดังนี้

ส่วนประกอบ จัดการ
ตัวควบคุมเซสชัน สถานะเซสชัน
ตัวจับเวลา
ตรรกะการจัดกลุ่ม
เครื่องควบคุมประเภทข้อมูล
การเก็บรวบรวมข้อมูล
เลเยอร์ที่เก็บ (ครอบคลุมการดำเนินการของ Health Connect) แทรกเซสชัน
แทรกประเภทข้อมูล
แทรกระยะการนอนหลับ
อ่านข้อมูลสรุปเซสชัน
เลเยอร์ UI (การแสดงผล): ระยะเวลา
ประเภทข้อมูลสด
ภาพการนอนหลับ

การแก้ปัญหา

ลักษณะปัญหา สาเหตุที่เป็นไปได้ ความละเอียด
ประเภทข้อมูลที่ขาดหายไป (เช่น อัตราการเต้นของหัวใจ) ไม่มีสิทธิ์เขียนหรือตัวกรองเวลาไม่ถูกต้อง ตรวจสอบว่าคุณได้ขอและผู้ใช้ได้ให้สิทธิ์ประเภทข้อมูลที่เฉพาะเจาะจงแล้ว ตรวจสอบว่า ReadRecordsRequest ใช้ TimeRangeFilter ที่ตรงกับเซสชัน ดูสิทธิ์
เซสชันเขียนไม่สำเร็จ การประทับเวลาที่ทับซ้อนกัน Health Connect อาจปฏิเสธบันทึกที่ทับซ้อนกับข้อมูลที่มีอยู่จากแอปเดียวกัน ตรวจสอบว่าstartTimeของเซสชันใหม่เกิดขึ้นหลังจากendTimeของเซสชันก่อนหน้า
ไม่มีการบันทึกข้อมูลเซ็นเซอร์ขณะนอนหลับ บริการที่ทำงานอยู่เบื้องหน้าถูกหยุดทำงานหรือไม่ทำงาน หากต้องการรวบรวมข้อมูลเซ็นเซอร์ข้ามคืนขณะที่หน้าจอปิดอยู่ คุณสามารถใช้บริการที่ทำงานอยู่เบื้องหน้ากับ foregroundServiceType="health" ได้
ระเบียนที่ซ้ำกันปรากฏขึ้น ไม่มี clientRecordId กำหนด clientRecordId ที่ไม่ซ้ำกันใน Metadata ของแต่ละระเบียน ซึ่งจะช่วยให้ Health Connect สามารถขจัดข้อมูลที่ซ้ำกันได้หากมีการเขียนข้อมูลเดียวกัน 2 ครั้งระหว่างการลองซิงค์อีกครั้ง ดูแนวทางปฏิบัติแนะนำ

ขั้นตอนการแก้ไขข้อบกพร่องที่พบบ่อย

ตรวจสอบสถานะสิทธิ์ โปรดเรียกใช้ getPermissionStatus() เสมอก่อนที่จะพยายามดำเนินการอ่านหรือเขียน ผู้ใช้สามารถเพิกถอนสิทธิ์ในการตั้งค่าระบบได้ทุกเมื่อ
ตรวจสอบโหมดการดำเนินการ หากแอปไม่ได้รวบรวมข้อมูลในเบื้องหลัง ให้ตรวจสอบว่าคุณได้ประกาศสิทธิ์ที่ถูกต้องในไฟล์ AndroidManifest.xml และผู้ใช้ไม่ได้ตั้งค่าแอปเป็นโหมด "จำกัดแบตเตอรี่"