Tối ưu hóa vị trí cho pin

Giới hạn quyền truy cập vị trí ở chế độ nền được giới thiệu trong Android 8.0 (API cấp độ 26) đã tập trung trở lại vào chủ đề: mức sử dụng dịch vụ vị trí ảnh hưởng thế nào đến tình trạng tiêu hao pin. Trang này trình bày một số phương pháp hay nhất liên quan đến dịch vụ vị trí và những việc bạn có thể làm ngay bây giờ để tăng hiệu suất pin cho ứng dụng. Việc áp dụng các phương pháp hay nhất này sẽ có lợi cho ứng dụng của bạn bất kể ứng dụng đang chạy phiên bản nền tảng nào.

Giới hạn quyền truy cập vị trí ở chế độ nền trong Android 8.0 đã tạo ra những thay đổi sau:

  • Tính năng truy cập vị trí ở chế độ nền được điều chỉnh và tính toán, đồng thời chỉ phân phối vài lần một giờ.
  • Các lần quét tìm Wi-Fi sẽ mang tính hạn chế hơn và việc cập nhật vị trí sẽ không được tính toán khi thiết bị vẫn kết nối với cùng một điểm truy cập tĩnh.
  • Phản hồi của tính năng khoanh vùng địa lý thay đổi từ hàng chục giây đến khoảng hai phút. Thay đổi này cải thiện đáng kể hiệu suất pin – tốt hơn gấp 10 lần trên một số thiết bị.

Trang này giả định rằng bạn đang sử dụng API Dịch vụ vị trí của Google. API này cho độ chính xác cao hơn và giảm tải pin hơn so với API vị trí khung. Đặc biệt, trang này xác định mức độ quen thuộc với API trình cung cấp vị trí kết hợp kết hợp các tín hiệu từ GPS, Wi-Fi và mạng di động, cũng như gia tốc kế, con quay hồi chuyển, từ kế và các cảm biến khác. Bạn cũng nên làm quen với API khoanh vùng địa lý được xây dựng ngoài API trình cung cấp vị trí kết hợp và được tối ưu hóa để cải thiện hiệu suất pin.

Tìm hiểu về tiêu hao pin

Việc thu thập thông tin vị trí và tiêu hao pin đều liên quan trực tiếp đến các khía cạnh sau:

  • Độ chính xác: Độ chính xác của dữ liệu vị trí. Nói chung, độ chính xác càng cao thì mức tiêu hao pin càng cao.
  • Tần suất: Tần suất việc vị trí được tính toán. Vị trí càng thường xuyên được tính toán, pin càng tiêu hao nhiều.
  • Độ trễ: Tốc độ phân phối dữ liệu vị trí. Độ trễ càng thấp, mức tiêu hao pin càng ít.

Độ chính xác

Bạn có thể chỉ định độ chính xác vị trí bằng cách sử dụng phương thức setPriority(), chuyển một trong các giá trị sau làm đối số:

  • PRIORITY_HIGH_ACCURACY cung cấp việc vị trí chính xác nhất có thể được tính toán bằng cách sử dụng nhiều thông tin đầu vào (nếu cần) (tùy chọn này sẽ bật GPS, Wi-Fi và di động cũng như sử dụng nhiều loại Bộ cảm biến) và có thể khiến tiêu hao pin đáng kể.
  • PRIORITY_BALANCED_POWER_ACCURACY cung cấp dịch vụ vị trí chính xác đồng thời tối ưu hóa nguồn điện. Rất hiếm khi sử dụng GPS. Thường sử dụng kết hợp thông tin Wi-Fi và di động để tính toán vị trí của thiết bị.
  • PRIORITY_LOW_POWER chủ yếu dựa vào trạm phát sóng di động và tránh đầu vào Wi-Fi và GPS, cung cấp độ chính xác tương đối (cấp thành phố) với mức tiêu hao pin tối thiểu.
  • PRIORITY_NO_POWER nhận vị trí từ các ứng dụng khác một cách bị động. Vị trí đã được tính toán từ trước cho các ứng dụng này.

Nhu cầu vị trí của hầu hết ứng dụng có thể được thỏa mãn bằng cách sử dụng nguồn điện cân bằng hoặc tùy chọn điện năng thấp. Bạn phải đảm bảo tính chính xác cao cho các ứng dụng đang chạy ở nền trước và yêu cầu cập nhật vị trí theo thời gian thực (ví dụ: ứng dụng liên kết (mapping)).

Tần suất

Bạn có thể chỉ định tần suất vị trí bằng hai phương pháp:

  • Sử dụng phương thức setinterval() để chỉ định khoảng thời gian tính toán vị trí cho ứng dụng của bạn.
  • Sử dụng setFastestInterval() để chỉ định khoảng thời gian mà vị trí được tính toán cho các ứng dụng khác sẽ phân phối cho ứng dụng của bạn.

Bạn nên chuyển giá trị lớn nhất có thể khi sử dụng setInterval(). Điều này đặc biệt đúng với tính năng thu thập thông tin vị trí ở chế độ nền, thường là nguyên nhân làm tiêu hao pin. Bạn nên sử dụng khoảng thời gian vài giây cho các trường hợp sử dụng nền trước. Giới hạn quyền truy cập vị trí ở chế độ nền được giới thiệu trong Android 8.0 thực hiện các chiến lược này, tuy thế ứng dụng của bạn nên cố gắng thực hiện các chiến lược đó trên thiết bị Android 7.0 trở xuống.

Độ trễ

Bạn có thể chỉ định độ trễ bằng phương thức setMaxWaitTime(), thông thường là chuyển giá trị lớn hơn vài lần so với khoảng thời gian được chỉ định trong setInterval(). Tùy chọn cài đặt này trì hoãn việc phân phối thông tin vị trí và nhiều cập nhật về vị trí có thể được phân phối theo lô. Hai thay đổi này giúp giảm thiểu mức tiêu hao pin.

Nếu ứng dụng của bạn không cần cập nhật vị trí ngay lập tức, bạn nên chuyển giá trị lớn nhất có thể về phương thức setMaxWaitTime(), điều này giúp giao dịch độ trễ hiệu quả hơn để cho hiệu suất dữ liệu tốt hơn và tiết kiệm pin hơn.

Khi sử dụng khoanh vùng địa lý, ứng dụng phải chuyển một giá trị lớn vào phương thức setNotificationResponsiveness() để duy trì nguồn điện. Bạn nên sử dụng giá trị từ năm phút trở lên.

Các trường hợp sử dụng dịch vụ vị trí

Phần này mô tả một số trường hợp thu thập thông tin vị trí điển hình, cùng với các đề xuất sử dụng tối ưu tính năng khoanh vùng địa lý và các API trình cung cấp vị trí kết hợp.

Các bản cập nhật chế độ hiển thị người dùng hoặc nền trước

Ví dụ: Một ứng dụng bản đồ cần các cập nhật thường xuyên, chính xác với độ trễ rất thấp. Mọi hoạt động cập nhật diễn ra ở nền trước: người dùng bắt đầu một hoạt động, sử dụng dữ liệu vị trí và sau đó dừng hoạt động đó sau thời gian ngắn.

Sử dụng phương thức setPriority() với giá trị PRIORITY_HIGH_ACCURACY hoặc PRIORITY_BALANCED_POWER_ACCURACY.

Khoảng thời gian chỉ định trong phương thức setInterval() tùy thuộc vào trường hợp sử dụng: trong trường hợp theo thời gian thực, hãy đặt giá trị thành vài giây; nếu không, hãy giới hạn ở vài phút (nên đặt ở khoảng hai phút hoặc nhiều hơn để giảm thiểu mức sử dụng pin).

Biết vị trí của thiết bị

Ví dụ: Một ứng dụng thời tiết muốn biết vị trí của thiết bị.

Sử dụng phương thức getLastLocation(), phương thức này sẽ trả về vị trí có sẵn gần nhất (trong một số ít trường hợp có thể là rỗng). Phương thức này cung cấp cách thức đơn giản để nhận thông tin vị trí và bạn không phải chịu chi phí liên quan đến việc chủ động yêu cầu cập nhật vị trí. Hãy sử dụng cùng với phương thức isLocationAvailable(), phương thức này sẽ trả về true khi vị trí được trả về bởi getLastLocation() được cập nhật hợp lý.

Bắt đầu cập nhật khi người dùng đang ở một vị trí cụ thể

Ví dụ: Yêu cầu cập nhật khi người dùng ở trong một khoảng cách nhất định so với cơ quan, nhà riêng hoặc một vị trí khác.

Sử dụng tính năng khoanh vùng địa lý kết hợp với bản cập nhật của trình cung cấp vị trí kết hợp. Yêu cầu cập nhật khi ứng dụng nhận được trình kích hoạt khoanh vùng địa lý đầu vào (entrance trigger) và xóa các bản cập nhật khi ứng dụng nhận được trình kích hoạt khoanh vùng địa lý đầu ra (exit trigger). Việc này đảm bảo ứng dụng chỉ nhận được thông báo cập nhật chi tiết về vị trí khi người dùng đã nhập một khu vực được xác định.

Quy trình công việc thông thường cho tình huống này có thể bao gồm việc hiển thị thông báo khi chuyển đổi vào (enter transition) tính năng khoanh vùng địa lý, đồng thời khởi chạy một hoạt động chứa mã để yêu cầu cập nhật khi người dùng nhấn vào thông báo.

Bắt đầu cập nhật dựa trên trạng thái hoạt động của người dùng

Ví dụ: Chỉ yêu cầu cập nhật khi người dùng đang lái xe hoặc đi xe đạp.

Sử dụng API Nhận dạng hoạt động cùng với thông tin cập nhật từ trình cung cấp vị trí kết hợp. Yêu cầu cập nhật khi phát hiện hoạt động được nhắm mục tiêu và xóa các bản cập nhật khi người dùng ngừng thực hiện hoạt động đó.

Quy trình công việc thông thường cho trường hợp sử dụng này có thể bao gồm việc hiển thị một thông báo cho hoạt động đã phát hiện và phát hành một hoạt động chứa mã để yêu cầu cập nhật khi người dùng nhấn vào thông báo đó.

Các bản cập nhật quyền truy cập thông tin vị trí ở chế độ nền lâu dài gắn với khu vực địa lý

Ví dụ: Người dùng muốn được thông báo khi thiết bị ở gần nhà bán lẻ.

Đây là trường hợp sử dụng tuyệt vời cho tính năng khoanh vùng địa lý. Vì trường hợp sử dụng này gần như chắc chắn có liên quan đến quyền truy cập vị trí ở chế độ nền, hãy sử dụng phương thức addGeofences(GeofencingRequest, PendingIntent).

Bạn nên đặt các tùy chọn cấu hình sau đây:

  • Nếu bạn đang theo dõi các chuyển đổi ở trạng thái dừng, hãy sử dụng phương thức setLoiteringDelay() chuyển giá trị trong khoảng năm phút trở xuống.

  • Sử dụng setNotificationResponsiveness(), chuyển giá trị khoảng năm phút. Tuy nhiên, hãy cân nhắc sử dụng giá trị khoảng mười phút nếu ứng dụng của bạn có thể kiểm soát việc trì hoãn thêm phản hồi.

Một ứng dụng chỉ có thể đăng ký tối đa 100 khoanh vùng địa lý một lúc. Trong trường hợp khi một ứng dụng muốn theo dõi số lượng lớn tùy chọn nhà bán lẻ, ứng dụng có thể phải đăng ký khoanh vùng địa lý lớn (ở cấp thành phố) và tự động đăng ký các khoanh vùng địa lý nhỏ hơn (đối với các vị trí trong thành phố) cho các cửa hàng trong phạm vi khoanh vùng địa lý lớn hơn. Khi người dùng nhập khoanh vùng địa lý lớn, các khoanh vùng địa lý nhỏ hơn có thể được thêm vào; khi người dùng thoát khỏi khoanh vùng địa lý lớn, các khoanh vùng địa lý nhỏ có thể bị xóa và các khoanh vùng địa lý có thể được đăng ký lại cho khu vực mới.

Các bản cập nhật quyền truy cập thông tin vị trí ở chế độ nền lâu dài không có thành phần ứng dụng hiển thị

Ví dụ: Một ứng dụng theo dõi vị trí một cách bị động

Hãy sử dụng phương thức setPriority() với tùy chọn PRIORITY_NO_POWER nếu có thể vì phương thức này gần như không làm tiêu hao pin. Nếu không thể sử dụng PRIORITY_NO_POWER, hãy sử dụng PRIORITY_BALANCED_POWER_ACCURACY hoặc PRIORITY_LOW_POWER, nhưng tránh sử dụng PRIORITY_HIGH_ACCURACY để duy trì tác vụ nền vì tùy chọn này làm tiêu hao pin đáng kể.

Nếu bạn cần nhiều dữ liệu vị trí hơn, hãy sử dụng dịch vụ vị trí thụ động bằng cách gọi phương thức setFastestInterval() chuyển giá trị nhỏ hơn giá trị bạn chuyển đến setInterval() Khi kết hợp với tùy chọn PRIORITY_NO_POWER, dịch vụ vị trí thụ động có thể phân phối vị trí được các ứng dụng khác tính toán mà không mất thêm chi phí.

Điều chỉnh tần suất bằng cách thêm độ trễ, sử dụng phương thức setMaxWaitTime(). Ví dụ: nếu bạn sử dụng phương thức setinterval() có giá trị khoảng 10 phút, bạn nên xem xét việc gọi setMaxWaitTime() với giá trị nằm trong khoảng từ 30 đến 60 phút. Khi sử dụng các tùy chọn này, vị trí được tính toán cho ứng dụng của bạn khoảng 10 phút một lần, nhưng ứng dụng chỉ được đánh thức 30 đến 60 phút một lần với một số dữ liệu vị trí có sẵn dưới dạng bản cập nhật theo lô. Phương pháp này đánh đổi độ trễ để có nhiều dữ liệu hơn và hiệu suất pin tốt hơn.

Thường xuyên cập nhật độ chính xác cao khi người dùng tương tác với các ứng dụng khác

Ví dụ: Một ứng dụng điều hướng hoặc thể dục vẫn tiếp tục hoạt động khi người dùng tắt màn hình hoặc mở một ứng dụng khác.

Sử dụng dịch vụ trên nền trước. Nếu tác vụ tốn kém có khả năng sẽ được ứng dụng của bạn thực hiện thay mặt người dùng, thì tốt nhất bạn nên thông báo cho người dùng về tác vụ đó. Một dịch vụ trên nền trước yêu cầu một thông báo liên tục. Để biết thêm thông tin, hãy xem bài viết Tổng quan về thông báo.

Các phương pháp hay nhất xác định vị trí

Việc triển khai các phương pháp hay nhất trong phần này giúp giảm mức sử dụng pin của ứng dụng.

Xóa bản cập nhật vị trí

Một nguyên nhân phổ biến gây tiêu hao pin không cần thiết là không xóa được thông tin cập nhật vị trí khi dữ liệu đó không còn cần thiết nữa. Điều này có thể xảy ra, chẳng hạn như khi một onStart() của hoạt động hoặc phương thức vòng đời onResume() chứa lệnh gọi đến requestlocationUpdates() mà không có lệnh gọi tương ứng đến removeLocationUpdates() trong onPause() hoặc onStop().

Bạn có thể sử dụng các thành phần nhận biết vòng đời để quản lý tốt hơn vòng đời của các hoạt động trong ứng dụng. Để biết thêm thông tin, vui lòng xem nội dung Xử lý vòng đời bằng các thành phần nhận biết vòng đời ,

Đặt thời gian chờ

Để tránh bị hao pin, hãy đặt thời gian chờ hợp lý khi dừng cập nhật vị trí. Thời gian chờ đảm bảo các bản cập nhật không tiếp tục vô thời hạn và bảo vệ ứng dụng trong các trường hợp thông báo cập nhật được yêu cầu nhưng không bị xóa (ví dụ: do lỗi trong mã).

Đối với yêu cầu từ trình cung cấp vị trí kết hợp, hãy thêm thời gian chờ bằng cách gọi setExpirationDuration(). Sự kiện này nhận được thông số đại diện cho thời gian tính bằng mili giây kể từ khi phương thức được gọi gần đây nhất. Bạn cũng có thể thêm thời gian chờ bằng cách gọi setExpirationTime(). Sự kiện này nhận được thông số thể hiện thời gian hết hạn tính bằng mili giây kể từ lần khởi động (root) gần đây nhất của hệ thống.

Để thêm thời gian chờ vào yêu cầu vị trí khoanh vùng địa lý, hãy gọi phương thức setExpirationDuration().

Yêu cầu theo lô (Batch)

Đối với tất cả các trường hợp sử dụng không phải trên nền trước, hãy tạo nhiều yêu cầu cùng lúc. Bạn có thể sử dụng phương thức setInterval() để chỉ định khoảng thời gian bạn muốn tính toán vị trí. Sau đó, hãy sử dụng phương thức setMaxWaitTime()để đặt khoảng thời gian mà vị trí được phân phối đến ứng dụng của bạn. Giá trị được chuyển đến phương thức setMaxWaitTime() phải là bội số của giá trị được chuyển đến phương thức setInterval(). Ví dụ: hãy xem xét yêu cầu vị trí sau:

Kotlin

val request = LocationRequest()
request.setInterval(10 * 60 * 1000)
request.setMaxWaitTime(60 * 60 * 1000)

Java

LocationRequest request = new LocationRequest();
request.setInterval(10 * 60 * 1000);
request.setMaxWaitTime(60 * 60 * 1000);

Trong trường hợp này, vị trí được tính toán khoảng mỗi mười phút và khoảng sáu điểm dữ liệu vị trí được phân phối theo lô khoảng mỗi giờ. Mặc dù bạn vẫn nhận được thông tin cập nhật vị trí khoảng mười phút một lần, nhưng bạn vẫn tiết kiệm được pin vì thiết bị chỉ bị đánh thức mỗi giờ một lần.

Sử dụng thông báo cập nhật vị trí thụ động

Đối với các trường hợp sử dụng trong nền, bạn nên hạn chế các cập nhật vị trí. Phiên bản Android 8.0 giới hạn thực hiện phương pháp này, nhưng các ứng dụng chạy trên các thiết bị cũ cần giới hạn quyền truy cập vị trí ở chế độ nền nhiều nhất có thể.

Nhiều khả năng khi ứng dụng của bạn chạy trong nền thì một ứng dụng khác có thể thường xuyên yêu cầu thông báo cập nhật vị trí ở nền trước. Dịch vụ vị trí cung cấp các bản cập nhật này cho ứng dụng. Hãy cân nhắc yêu cầu vị trí sau đây bởi chúng sẽ có thể tiêu thụ dữ liệu vị trí:

Kotlin

val request = LocationRequest()
request.setInterval(15 * 60 * 1000)
request.setFastestInterval(2 * 60 * 1000)

Java

LocationRequest request = new LocationRequest();
request.setInterval(15 * 60 * 1000);
request.setFastestInterval(2 * 60 * 1000);

Trong ví dụ trước, vị trí được tính toán cho ứng dụng của bạn khoảng 15 phút một lần. Nếu các ứng dụng khác yêu cầu vị trí, dữ liệu sẽ được cung cấp cho ứng dụng của bạn trong khoảng thời gian tối đa là hai phút.

Mặc dù việc sử dụng dịch vụ vị trí thụ động không làm tiêu hao pin, nhưng hãy thận trọng hơn trong các trường hợp mà việc tiếp nhận dữ liệu vị trí sẽ kích hoạt các hoạt động tốn nhiều chi phí là CPU hoặc I/O. Để giảm thiểu chi phí pin, khoảng thời gian chỉ định trong setFastestInterval() không được quá nhỏ.

Bạn có thể cải thiện đáng kể hiệu suất pin trên thiết bị của người dùng bằng cách làm theo các đề xuất trên trang này. Người dùng của bạn ít có khả năng xóa các ứng dụng không làm hao pin của họ.