我正在使用信标库来通过前台服务和持久通知扫描信标。我已经在Android 9.0和7.0上对此进行了测试,该应用程序可以按预期工作,并且每30秒将扫描的信标发送到服务器。现在,我正在尝试向应用程序添加位置扫描,以便它每30秒检索一次位置更新。我正在使用Google Play API,并以30秒的间隔设置了位置请求。然后,我在我的应用程序类中创建了一个FusedLocationProvider客户端,因此我给了它我应用程序(而非活动)的上下文。然后,我将请求和以下回调发送给客户端:
locationCallback = new LocationCallback()
{
@Override
public void onLocationResult(LocationResult locationResult)
{
if ( locationResult != null )
{
Log.d(TAG, "location acquired: " + locationResult.getLastLocation());
beaconContainer.setLocation(locationResult.getLastLocation());
}
}
};
beaconContainer对象保存一个信标列表和最新位置(以及使用LocalTime.now()获取最新位置的时间戳),并每30秒将它们发送到服务器。最初,该应用似乎可以正常工作,并且位置时间戳记是在向服务器发送请求后的30秒内。但是,经过一段时间(屏幕已关闭一段时间)后,似乎未调用回调中的onLocationResult方法并且未更新位置。例如,服务器请求在12:34发出,但位置在10:21更新。请注意,信标扫描仍按预期正确执行。
我想知道这是因为我测试过的手机是固定的,还是因为我没有使用服务来进行位置更新。在我看来,这似乎是前者,因为我的应用程序具有前台服务(ble扫描程序)和持久通知,因此根据文档,它位于前台且不应受到背景限制。如果是后者,我如何将信标库的前台服务与位置扫描融合在一起,以使它们都能按预期运行。
谢谢。
编辑:
答案 0 :(得分:1)
The documentation for FusedLocationProviderClient
indicates that on Android 8+, if the app is not in the foreground, you will only get updates a "few times each hour". See here. This is likely because the implementation inside Google Play Services uses the JobScheduler on Android 8+ to get around background service limits, and jobs are limited to running every 15 minutes +/- 5 minutes in the background. Since Google Play Services APIs are closed source and proprietary, it is difficult to say more about its internal implementation, but it is unlikely that it takes into account that your app has a foreground service. (The Android Beacon Library, by contrast, is explicitly designed to behave differently when configured with a Foreground Service so you get more frequent updates.)
It's unclear how the FusedLocationProviderClient
works differently in the background on Android 7. It may not work differently at all, and may follow the pattern described above in the background simply if your app targets SDK 26 or higher. You'd have to test to make sure -- effectively reverse engineering Google Play Services. Even if you do figure it out, the behavior might change in the next Google Play Services version, and you'll never know about it unless you reverse-engineer it again. This is the peril of using closed-source SDKs.
An alternative would be to instead use the open-source location APIs provided by Android.
LocationManager locationManager = (LocationManager)
this.getSystemService(Context.LOCATION_SERVICE);
try {
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 400l, (float) 1000.0, this); //You can also use LocationManager.GPS_PROVIDER and LocationManager.PASSIVE_PROVIDER
}
catch (SecurityException e) {
Log.d(TAG, "Can't get location -- permission denied");
}
Of course, you'll want to adjust the accuracy and update interval to suit your needs and conserve battery. And you will certainly find dropouts in callbacks when your phone enters Doze mode. But you should be able to use the above in your Application class as you describe in your question without the annoyingly opaque behaviors added by Google Play Services.