如何等待 requestLocationUpdates() 回调意图完成?
How to wait for requestLocationUpdates() callback intent to finish?
我想等待 FusedLocationProviderClient.requestLocationUpdates() 中的回调意图完成。带超时的 while 循环是最好的解决方案吗?下面是一个例子,没有超时。
通常我会使用 startWakefulService() 来等待异步服务完成,但我不知道如何将它与 requestLocationUpdates() 一起使用。
Task t = flpc.requestLocationUpdates(locationRequest, pe);
while (! t.isSuccessful()) {
Log.v(TAG, "Waiting for result...");
}
如果你对 RxJava/RxAndroid 有点熟悉,你可以将你的方法调用包装在一个 Observable 中(或者 Callable,Single,任何你认为最好的),运行 它在另一个线程上比 UI 然后一旦你从你的方法中得到结果,你就会在主线程上收到它,然后用它做任何你想做的事。
在代码中它看起来像这样:
Observable.fromCallable(() -> flpc.requestLocationUpdates(locationRequest, pe))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(task -> onLocationUpdatesSuccess(task), throwable -> Log.e(TAG, throwable.getMessage()));
否则,另一种解决方案是将您的方法包装在 AsyncTask 中,例如,您最终会得到这样的结果:
new AsyncTask<Void, Void, Task>() {
@Override
protected Task doInBackground(Void... params) {
return flpc.requestLocationUpdates(locationRequest, pe);
}
@Override
protected void onPostExecute(Task task) {
onLocationUpdatesSuccess(task)
}
}.execute();
这是我最后做的:
使用手动唤醒锁。在 class 中声明一个静态唤醒锁变量。还定义了两个方法:acquire() 和 release()。
acquire() 实例化唤醒锁并在您的 class 中为其分配静态唤醒锁变量。它是一个实例方法(不是静态的),因为它使用需要上下文的 PowerManager。
release() 是一个静态方法,因此其他 classes 可以调用它。它释放唤醒锁。我使用了一个带有唤醒锁计数器的单例唤醒锁,在调用时递减计数器,并在计数器为零时释放唤醒锁。但是计数器是完全可选的。
所有这一切的 "trick" 是创建实例唤醒锁并将其分配给静态变量。这允许在无法访问我的 class 实例的服务中修改唤醒锁。
不是从 class 外部调用 finish(),更简洁的解决方案是使用 Task.OnCompleteListener() 调用 finish()。 requestLocationUpdates() returns 一个任务对象。
这是我仅获取 1 个位置的解决方案:
private fun getNewLocation(): Single<Location> =
Single.create { emitter ->
locationClient.requestLocationUpdates(locationRequest, object : LocationCallback() {
override fun onLocationResult(result: LocationResult) {
locationClient.removeLocationUpdates(this)
val location = result.locations.firstOrNull()
if (location != null) {
emitter.onSuccess(location)
} else {
emitter.onError(NullPointerException("Null location"))
}
}
override fun onLocationAvailability(result: LocationAvailability) {
if (!result.isLocationAvailable) {
locationClient.removeLocationUpdates(this)
emitter.onError(IllegalStateException("Location not available"))
}
}
}, Looper.getMainLooper())
}
其中 locationRequest
看起来像:
private val locationRequest =
LocationRequest()
.setExpirationDuration(TimeUnit.SECONDS.toMillis(30L))
.setInterval(TimeUnit.SECONDS.toMillis(15L))
.setNumUpdates(1)
我想等待 FusedLocationProviderClient.requestLocationUpdates() 中的回调意图完成。带超时的 while 循环是最好的解决方案吗?下面是一个例子,没有超时。
通常我会使用 startWakefulService() 来等待异步服务完成,但我不知道如何将它与 requestLocationUpdates() 一起使用。
Task t = flpc.requestLocationUpdates(locationRequest, pe);
while (! t.isSuccessful()) {
Log.v(TAG, "Waiting for result...");
}
如果你对 RxJava/RxAndroid 有点熟悉,你可以将你的方法调用包装在一个 Observable 中(或者 Callable,Single,任何你认为最好的),运行 它在另一个线程上比 UI 然后一旦你从你的方法中得到结果,你就会在主线程上收到它,然后用它做任何你想做的事。
在代码中它看起来像这样:
Observable.fromCallable(() -> flpc.requestLocationUpdates(locationRequest, pe))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(task -> onLocationUpdatesSuccess(task), throwable -> Log.e(TAG, throwable.getMessage()));
否则,另一种解决方案是将您的方法包装在 AsyncTask 中,例如,您最终会得到这样的结果:
new AsyncTask<Void, Void, Task>() {
@Override
protected Task doInBackground(Void... params) {
return flpc.requestLocationUpdates(locationRequest, pe);
}
@Override
protected void onPostExecute(Task task) {
onLocationUpdatesSuccess(task)
}
}.execute();
这是我最后做的:
使用手动唤醒锁。在 class 中声明一个静态唤醒锁变量。还定义了两个方法:acquire() 和 release()。
acquire() 实例化唤醒锁并在您的 class 中为其分配静态唤醒锁变量。它是一个实例方法(不是静态的),因为它使用需要上下文的 PowerManager。
release() 是一个静态方法,因此其他 classes 可以调用它。它释放唤醒锁。我使用了一个带有唤醒锁计数器的单例唤醒锁,在调用时递减计数器,并在计数器为零时释放唤醒锁。但是计数器是完全可选的。
所有这一切的 "trick" 是创建实例唤醒锁并将其分配给静态变量。这允许在无法访问我的 class 实例的服务中修改唤醒锁。
不是从 class 外部调用 finish(),更简洁的解决方案是使用 Task.OnCompleteListener() 调用 finish()。 requestLocationUpdates() returns 一个任务对象。
这是我仅获取 1 个位置的解决方案:
private fun getNewLocation(): Single<Location> =
Single.create { emitter ->
locationClient.requestLocationUpdates(locationRequest, object : LocationCallback() {
override fun onLocationResult(result: LocationResult) {
locationClient.removeLocationUpdates(this)
val location = result.locations.firstOrNull()
if (location != null) {
emitter.onSuccess(location)
} else {
emitter.onError(NullPointerException("Null location"))
}
}
override fun onLocationAvailability(result: LocationAvailability) {
if (!result.isLocationAvailable) {
locationClient.removeLocationUpdates(this)
emitter.onError(IllegalStateException("Location not available"))
}
}
}, Looper.getMainLooper())
}
其中 locationRequest
看起来像:
private val locationRequest =
LocationRequest()
.setExpirationDuration(TimeUnit.SECONDS.toMillis(30L))
.setInterval(TimeUnit.SECONDS.toMillis(15L))
.setNumUpdates(1)