Java 在 Android 的 IntentService 中等待异步回调
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21964375/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Waiting for asynchronous callback in Android's IntentService
提问by caw
I have an IntentService
that starts an asynchronous task in another class and should then be waiting for the result.
我有一个IntentService
在另一个类中启动异步任务,然后应该等待结果。
The problem is that the IntentService
will finish as soon as the onHandleIntent(...)
method has finished running, right?
问题是方法一运行IntentService
完成就会onHandleIntent(...)
结束,对吗?
That means, normally, the IntentService
will immediately shut down after starting the asynchronous task and will not be there anymore to receive the results.
这意味着,通常情况IntentService
下,启动异步任务后将立即关闭,并且不再在那里接收结果。
public class MyIntentService extends IntentService implements MyCallback {
public MyIntentService() {
super("MyIntentService");
}
@Override
protected final void onHandleIntent(Intent intent) {
MyOtherClass.runAsynchronousTask(this);
}
}
public interface MyCallback {
public void onReceiveResults(Object object);
}
public class MyOtherClass {
public void runAsynchronousTask(MyCallback callback) {
new Thread() {
public void run() {
// do some long-running work
callback.onReceiveResults(...);
}
}.start();
}
}
How can I make the snippet above work? I've already tried putting Thread.sleep(15000)
(arbitrary duration) in onHandleIntent(...)
after starting the task. Itseems to work.
我怎样才能使上面的代码片段工作?我已经尝试在开始任务后放入Thread.sleep(15000)
(任意持续时间)onHandleIntent(...)
。它似乎工作。
But it definitely doesn't seem to be clean solution. Maybe there are even some serious problems with that.
但这绝对不是干净的解决方案。也许这甚至存在一些严重的问题。
Any better solution?
有什么更好的解决办法吗?
采纳答案by corsair992
Use the standard Service
class instead of IntentService
, start your asynchronous task from the onStartCommand()
callback, and destroy the Service
when you receive the completion callback.
使用标准Service
类而不是IntentService
,从onStartCommand()
回调开始异步任务,并Service
在收到完成回调时销毁。
The issue with that would be to correctly handle the destruction of the Service
in the case of concurrently running tasks as a result of the Service
being started again while it was already running. If you need to handle this case, then you might need to set up a running counter or a set of callbacks, and destroy the Service
only when they are all completed.
这样做的问题是Service
在并发运行任务的情况下正确处理销毁,因为Service
它已经在运行时再次启动。如果您需要处理这种情况,那么您可能需要设置一个运行计数器或一组回调,并Service
在它们全部完成时销毁它们。
回答by flx
You are doomed without changing MyOtherClass
.
你注定不改MyOtherClass
。
With changing that class you have two options:
通过更改该类,您有两个选择:
- Make an synchronous call.
IntentService
is already spawning a backgroundThread
for you. - Return the newly created
Thread
inrunAsynchronousTask()
and calljoin()
on it.
- 进行同步调用。
IntentService
已经Thread
为您生成背景。 - 返回新创建的
Thread
inrunAsynchronousTask()
并调用join()
它。
回答by keerthy
If you are still looking for ways to use Intent Service for asynchronous callback, you can have a wait and notify on thread as follows,
如果您仍在寻找使用 Intent Service 进行异步回调的方法,您可以按如下方式在线程上进行等待和通知,
private Object object = new Object();
@Override
protected void onHandleIntent(Intent intent) {
// Make API which return async calback.
// Acquire wait so that the intent service thread will wait for some one to release lock.
synchronized (object) {
try {
object.wait(30000); // If you want a timed wait or else you can just use object.wait()
} catch (InterruptedException e) {
Log.e("Message", "Interrupted Exception while getting lock" + e.getMessage());
}
}
}
// Let say this is the callback being invoked
private class Callback {
public void complete() {
// Do whatever operation you want
// Releases the lock so that intent service thread is unblocked.
synchronized (object) {
object.notifyAll();
}
}
}
回答by Matt Logan
My favorite option is to expose two similar methods, for example:
我最喜欢的选择是公开两个类似的方法,例如:
public List<Dog> getDogsSync();
public void getDogsAsync(DogCallback dogCallback);
Then the implementation could be as follows:
那么实现可能如下:
public List<Dog> getDogsSync() {
return database.getDogs();
}
public void getDogsAsync(DogCallback dogCallback) {
new AsyncTask<Void, Void, List<Dog>>() {
@Override
protected List<Dog> doInBackground(Void... params) {
return getDogsSync();
}
@Override
protected void onPostExecute(List<Dog> dogs) {
dogCallback.success(dogs);
}
}.execute();
}
Then in your IntentService
you can call getDogsSync()
because it's already on a background thread.
然后在您IntentService
可以调用,getDogsSync()
因为它已经在后台线程上。
回答by Matt Accola
I agree with corsair992 that typically you should not have to make asynchronous calls from an IntentService because IntentService already does its work on a worker thread. However, if you mustdo so you can use CountDownLatch.
我同意 corsair992 的观点,通常你不应该从 IntentService 进行异步调用,因为 IntentService 已经在工作线程上完成了它的工作。但是,如果您必须这样做,您可以使用CountDownLatch。
public class MyIntentService extends IntentService implements MyCallback {
private CountDownLatch doneSignal = new CountDownLatch(1);
public MyIntentService() {
super("MyIntentService");
}
@Override
protected final void onHandleIntent(Intent intent) {
MyOtherClass.runAsynchronousTask(this);
doneSignal.await();
}
}
@Override
public void onReceiveResults(Object object) {
doneSignal.countDown();
}
public interface MyCallback {
public void onReceiveResults(Object object);
}
public class MyOtherClass {
public void runAsynchronousTask(MyCallback callback) {
new Thread() {
public void run() {
// do some long-running work
callback.onReceiveResults(...);
}
}.start();
}
}
回答by Tom Lubitz
I agree, it probably makes more sense to use Service
directly rather than IntentService
, but if you are using Guava, you can implement an AbstractFuture
as your callback handler, which lets you conveniently ignore the details of synchronization:
我同意,Service
直接使用可能比使用更有意义IntentService
,但是如果您使用的是Guava,您可以实现 anAbstractFuture
作为您的回调处理程序,这样您就可以方便地忽略同步的细节:
public class CallbackFuture extends AbstractFuture<Object> implements MyCallback {
@Override
public void onReceiveResults(Object object) {
set(object);
}
// AbstractFuture also defines `setException` which you can use in your error
// handler if your callback interface supports it
@Override
public void onError(Throwable e) {
setException(e);
}
}
AbstractFuture
defines get()
which blocks until the set()
or setException()
methods are called, and returns a value or raises an exception, respectively.
AbstractFuture
分别定义在调用或方法get()
之前哪些块,并分别返回值或引发异常。set()
setException()
Then your onHandleIntent
becomes:
然后你onHandleIntent
变成:
@Override
protected final void onHandleIntent(Intent intent) {
CallbackFuture future = new CallbackFuture();
MyOtherClass.runAsynchronousTask(future);
try {
Object result = future.get();
// handle result
} catch (Throwable t) {
// handle error
}
}