等待Android IntentService中的异步回调

时间:2014-02-23 04:54:34

标签: java android asynchronous intentservice

我有一个IntentService在另一个类中启动异步任务,然后应该等待结果。

问题是,只要IntentService方法运行完毕,onHandleIntent(...)就会完成,对吗?

这意味着,通常情况下,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();
    }

}

如何让上面的代码段工作?我已经尝试在启动任务后在Thread.sleep(15000)中添加onHandleIntent(...)(任意持续时间)。它似乎工作。

但它绝对不是一个干净的解决方案。也许甚至有一些严重的问题。

有更好的解决方案吗?

6 个答案:

答案 0 :(得分:18)

使用标准Service类而不是IntentService,从onStartCommand()回调启动异步任务,并在收到完成回调时销毁Service

这个问题是在Service已经运行时再次启动Service的情况下,在同时运行任务的情况下正确处理Service的销毁。如果你需要处理这种情况,那么你可能需要设置一个正在运行的计数器或一组回调,并且只有当它们全部完成时才销毁{{1}}。

答案 1 :(得分:10)

我同意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();
    }

}

答案 2 :(得分:6)

如果您仍在寻找使用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();
        }   
    }
}

答案 3 :(得分:2)

我最喜欢的选择是公开两种类似的方法,例如:

public List<Dog> getDogsSync();
public void getDogsAsync(DogCallback dogCallback);

然后实施如下:

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();
}

然后在您的IntentService中,您可以拨打getDogsSync(),因为它已经在后台主题中。

答案 4 :(得分:1)

你注定没有改变MyOtherClass

通过更改该课程,您有两种选择:

  1. 进行同步通话。 IntentService已经为您生成了背景Thread
  2. Thread中返回新创建的runAsynchronousTask()并在其上调用join()

答案 5 :(得分:0)

我同意,直接使用Service而不是IntentService更有意义,但如果您使用Angular 2's router documentation,则可以实施AbstractFuture作为回调handler,它可以让你方便地忽略同步的细节:

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定义get(),阻止调用set()setException()方法,并分别返回值或引发异常。

然后您的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
        }
    }