Android 8.0 后台位置限制

问题

客户反映在Android 8.0手机上,当应用锁屏或者按Home键处于后台的情况下,Goolgle地图当前实时位置更新失败。

原因

为了减少电量消耗,Android 8.0会限制处于后台应用获取当前位置的频率,而且不论当前应用的目标SDK是哪个版本。

1
Important note : As a starting point, we only allow the background app to receive location updates several times an hour. We will continue to optimize the location update interval based on system impact and developer feedback throughout the preview period.

处于后台的应用只能实现一个小时几次的实时位置更新,当应用处于前台,实时位置更新功能和低版本的一样,不会受到次数限制。
对于需要频繁获取实时位置的应用,Google对此提供了优化办法。

优化应用位置获取

通过执行下列操作之一来提高位置更新的检索频率:

  • 将应用转至前台

  • 在应用中使用前台服务.需要注意的是当激活该服务的时候,需要在通知栏显示一个持续的通知

  • 使用Geofencing(GeofencingApi接口)之类的API,google对这些api进行了优化以尽可能减少电量消耗。

  • 使用被动定位监听器,它可以增加位置更新的获取频率

受影响的APIs

当应用处于后台,一下api会受到影响

  • Fused Location Provider(FLP)

  • Geofencing

  • GNSS Measurements and GNSS Navigation Messages`

  • Location Manager

官网链接

代码实践

在应用中启动一个Foreground Service来提高实时位置获取频率,本应用使用Fused Location Provider获取当前定位

创建一个前台服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

public class KeepAliveService extends Service {
private static final String TAG = "KeepAliveService";

@Override
public void onCreate() {
super.onCreate();
LogUtil.e(TAG,"onCreate");
}


@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent == null) return super.onStartCommand(intent, flags, startId);
postNotification();
LogUtil.e(TAG,"onStartCommand");
return START_REDELIVER_INTENT;
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
LogUtil.e(TAG,"onBind");
return null;
}

private void postNotification(){
Intent intent = new Intent(this, MapActivity.class);
Intent[] intents = new Intent[1];
intents[0] = intent;
PendingIntent notificationPendingIntent = PendingIntent.getActivities(this, 0, intents, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(this, NotificationChannel.DEFAULT_CHANNEL_ID)
.setSmallIcon(R.drawable.pippa_smallicon)
.setContentTitle("PiPPA")
.setContentIntent(notificationPendingIntent)
.build();


startForeground(110, notification);
}


@Override
public void onDestroy() {
super.onDestroy();
LogUtil.e(TAG,"onDestroy");
stopForeground(true);
}
}

在AndroidManifest.xml文件中配置

1
2
3
4
5
6
7
8
<!-- custom service : keep alive-->
<service
android:name="com.easybike.service.KeepAliveService"
android:enabled="true">
<intent-filter>
<action android:name="updateSystem" />
</intent-filter>
</service>

在MapActivity中开启服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
startKeepAliveService();
}

public void startKeepAliveService(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
LogUtil.e(TAG,"startKeepAliveService");
startForegroundService(new Intent(this, KeepAliveService.class));
// startServ、ice(new Intent(this, KeepAliveService.class));
}
}

@Override
protected void onDestroy() {
super.onDestroy();
...
stopService(new Intent(this,KeepAliveService.class));

}
坚持原创技术分享,您的支持将鼓励我继续创作!