尝试访问 PlacesClient.findCurrentPlace() 时获取 com.android.volley.TimeoutError
Getting com.android.volley.TimeoutError when trying to access PlacesClient.findCurrentPlace()
每次通过 FusedLocationProviderClient.requestLocationUpdates()
获取位置更新时,我都需要访问 PlacesClient.findCurrentPlace()。
我决定通过在传递给 FusedLocationProviderClient.requestLocationUpdates()
:
的 PendingIntent
调用的 BroadcastReceiver
中排队 OneTimeWorkRequest
来做到这一点
public class LocationReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
WorkRequest locationRequest = new OneTimeWorkRequest.Builder(HeartBeatWorker.class)
.build();
WorkManager.getInstance(context).enqueue(locationRequest);
}
}
但是,有时 Worker
的 doWork
从 Places SDK 调用返回的 Task<FindCurrentPlaceResponse>
中获取 com.android.volley.TimeoutError
:
@Override
public Result doWork() {
// Initialize the SDK
Places.initialize(getApplicationContext(), "<my API key>");
// Create a new Places client instance
PlacesClient placesClient = Places.createClient(getApplicationContext());
// Use fields to define the data types to return.
List<Place.Field> placeFields = new ArrayList<>();
placeFields.add(Place.Field.NAME);
placeFields.add(Place.Field.TYPES);
// Use the builder to create a FindCurrentPlaceRequest.
FindCurrentPlaceRequest request = FindCurrentPlaceRequest.newInstance(placeFields);
if (ContextCompat.checkSelfPermission(getApplicationContext(),
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
// Call Places SDK to get current PlaceLikelihoods
Task<FindCurrentPlaceResponse> placeResponse =
placesClient.findCurrentPlace(request);
placeResponse.addOnCompleteListener(new OnCompleteListener<FindCurrentPlaceResponse>() {
@Override
public void onComplete(@NonNull Task<FindCurrentPlaceResponse> task) {
if (task.isSuccessful()) {
...
} else {
// sometimes I fall here, with status code 15.
// Looking into it, the error turns out to be:
// com.android.volley.TimeoutError
Exception exception = task.getException();
if (exception instanceof ApiException) {
ApiException apiException = (ApiException) exception;
Log.d(MainActivity.LOG_TAG, "HeartBeatWorker: Place not found: " + apiException.getStatusCode());
}
}
}
});
} else {
Log.d(MainActivity.LOG_TAG, "HeartBeatWorker: No ACCESS_FINE_LOCATION permission: HeartBeatWorker returning");
}
return Result.success();
}
我知道 Android 执行相关 power management restrictions 可能会导致网络(Places SDK 调用可能需要)不可用。
但是,即使应用程序未处于打瞌睡模式并且它仍处于 App Standby Bucket = 10(即 Active)并且不应有任何网络限制,我也会收到错误消息。
那么错误的原因可能是什么?
我找到了答案here:
A short time after the screen turns off while the device is on
battery, Doze restricts network access and defers jobs and syncs.
我忽略了这一点,因为它没有在文档的主要 Doze guide 中明确提到,它仍然坚持设备也应该静止才能进入打瞌睡:
If a user leaves a device unplugged and stationary for a period of
time, with the screen off, the device enters Doze mode.
每次通过 FusedLocationProviderClient.requestLocationUpdates()
获取位置更新时,我都需要访问 PlacesClient.findCurrentPlace()。
我决定通过在传递给 FusedLocationProviderClient.requestLocationUpdates()
:
PendingIntent
调用的 BroadcastReceiver
中排队 OneTimeWorkRequest
来做到这一点
public class LocationReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
WorkRequest locationRequest = new OneTimeWorkRequest.Builder(HeartBeatWorker.class)
.build();
WorkManager.getInstance(context).enqueue(locationRequest);
}
}
但是,有时 Worker
的 doWork
从 Places SDK 调用返回的 Task<FindCurrentPlaceResponse>
中获取 com.android.volley.TimeoutError
:
@Override
public Result doWork() {
// Initialize the SDK
Places.initialize(getApplicationContext(), "<my API key>");
// Create a new Places client instance
PlacesClient placesClient = Places.createClient(getApplicationContext());
// Use fields to define the data types to return.
List<Place.Field> placeFields = new ArrayList<>();
placeFields.add(Place.Field.NAME);
placeFields.add(Place.Field.TYPES);
// Use the builder to create a FindCurrentPlaceRequest.
FindCurrentPlaceRequest request = FindCurrentPlaceRequest.newInstance(placeFields);
if (ContextCompat.checkSelfPermission(getApplicationContext(),
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
// Call Places SDK to get current PlaceLikelihoods
Task<FindCurrentPlaceResponse> placeResponse =
placesClient.findCurrentPlace(request);
placeResponse.addOnCompleteListener(new OnCompleteListener<FindCurrentPlaceResponse>() {
@Override
public void onComplete(@NonNull Task<FindCurrentPlaceResponse> task) {
if (task.isSuccessful()) {
...
} else {
// sometimes I fall here, with status code 15.
// Looking into it, the error turns out to be:
// com.android.volley.TimeoutError
Exception exception = task.getException();
if (exception instanceof ApiException) {
ApiException apiException = (ApiException) exception;
Log.d(MainActivity.LOG_TAG, "HeartBeatWorker: Place not found: " + apiException.getStatusCode());
}
}
}
});
} else {
Log.d(MainActivity.LOG_TAG, "HeartBeatWorker: No ACCESS_FINE_LOCATION permission: HeartBeatWorker returning");
}
return Result.success();
}
我知道 Android 执行相关 power management restrictions 可能会导致网络(Places SDK 调用可能需要)不可用。 但是,即使应用程序未处于打瞌睡模式并且它仍处于 App Standby Bucket = 10(即 Active)并且不应有任何网络限制,我也会收到错误消息。 那么错误的原因可能是什么?
我找到了答案here:
A short time after the screen turns off while the device is on battery, Doze restricts network access and defers jobs and syncs.
我忽略了这一点,因为它没有在文档的主要 Doze guide 中明确提到,它仍然坚持设备也应该静止才能进入打瞌睡:
If a user leaves a device unplugged and stationary for a period of time, with the screen off, the device enters Doze mode.