【问题标题】:How to execute RoboSpice requests synchronously?如何同步执行 RoboSpice 请求?
【发布时间】:2014-04-23 11:36:50
【问题描述】:

如何同步执行 RoboSpice 请求?可能吗?我想在 IntentService 中使用 RoboSpice。

编辑:

有时需要同步执行某些事情,例如在服务中。在我最近的项目中,我必须对一些不同类型的请求进行排队,并且我想将 IntentService 与 RoboSpice 一起使用。在我的情况下,当我执行不同的请求时,我需要等待来自request1 的结果,然后将数据从它传递到request2 并执行它。

我想要某种批处理请求队列。假设我们有两种类型的请求:request1request2request2需要request1获取的数据:

  1. 执行request1
  2. 等一下
  3. 获取request1获取的数据并传递给request2
  4. 执行request2
  5. 等一下
  6. 转到 1。

我想使用 IntentService(队列),但由于异步,它在启动请求后死掉了。

在我看来,使用监听器或 CountDownLatch 并不是最好的方法。

【问题讨论】:

  • 我也有同样的问题,正在解决中:(

标签: robospice


【解决方案1】:

根据 Riccardo Ciovatti on the RoboSpice mailing list 的建议,您的问题的直接答案是:

final CountDownLatch latch = new CountDownLatch(1);

final YourRequest request = new YourRequest();
spiceManager.execute(request, new RequestListener<YourResponse>() {

    @Override
    public void onRequestFailure(SpiceException spiceException) {
        latch.countDown();
    }

    @Override
    public void onRequestSuccess(YourResponse response) {
        latch.countDown();
    }
});

latch.await();

但这不是一个好的习惯用法,除非它在后台线程上执行。异步处理是 RoboSpice 的基本特性;它使 UI 线程保持空闲。

【讨论】:

  • 新问题不是关于同步请求,而是如何链接它们。在这种情况下,从第一个的侦听器执行第二个请求。
  • @Snicolas 我一直在寻找一种简单的方法来同步执行 RoboSpice 请求并且不情愿地选择了这种模式。我到处都看到它讨论了由于阻塞 UI 线程而将其视为有效要求,但是如果您不从 UI 线程执行它怎么办,在我的情况下,我想在 performFiltering 方法中执行它Filter。此方法从工作线程执行,因此无需将执行卸载到服务。似乎是不必要的开销。
  • @darnmason,你的评论让我有点困惑。如果要同步执行请求,只需执行它的 getDataFromNetwork 方法。在您评论的最后,您不希望使用服务来执行您的请求,但这是 RS 的精髓。如果您想链接请求,那么 Ricardo 的方法就可以了。但我同意,RS 可以提供一种替代方法,您可以在其中获得结果的未来,但很难获得侦听器具有不同回调的细粒度语义。如果您有明确的 API 可以访问 RS,请提交 Github 问题。
【解决方案2】:

在 IntentService 中使用 RoboSpice。在 CountDownLatch 的帮助下解决了这个问题。假设我们有 2 个不同的 SpiceManagers 和一些 syncMethods 在 IntentService 中按顺序执行。

全局

private final SpiceManager aSpiceManager =
       new SpiceManager(ASpiceService.class);
private final SpiceManager bSpiceManager =
       new SpiceManager(BSpiceService.class);

private CountDownLatch handleIntentLatch;

onHandleIntent:在我们执行 syncMethodA 之前 - 我们用 1 初始化我们的 CountDownLatch。在执行 syncMethodA 之后,我们在我们的锁存器上 await() for countDown()。当稍后某些方法将在我们的闩锁上调用 countDown() 至少一次 - 方法 onHandleIntent 将继续执行并完成,这将触发 IntentService onDestroy() 回调。

@Override
protected void onHandleIntent(Intent intent) {
    handleIntentLatch = new CountDownLatch(1);

    syncMethodA();

    try {
        handleIntentLatch.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

syncMethodA(): 假设我们需要依次启动一些同步方法(syncMethodA,其中回调执行syncMethodB等)。

private void syncMethodA() {
    SpiceRequest requestA = new SpiceRequest();

    if (!aSpiceManager.isStarted()) {
        LogUtils.LOGD(TAG, "starting aSpiceManager");
        aSpiceManager.start(getApplicationContext());
    }

    aSpiceManager.execute(requestA , new RequestListener<ResponseA>() {
        @Override
        public void onRequestSuccess(final ResponseA responseA) {
            // SOME LOGIC

            syncMethodB();

            // SOME LOGIC

        @Override
        public void onRequestFailure(SpiceException spiceException) {
            handleIntentLatch.countDown();
            // SOME LOGIC
        }
    });
}

syncMethodB、syncMethodC 等都是一样的——在 onRequestSuccess 我们开始下一个 syncMethodX。在 onRequestFailure 中,我们 countDown() 我们的闩锁 (handleIntentLatch)。

非常重要!!! 在顺序的最后一个 syncMethodX 中(完成后我们希望 onHandleIntent 方法继续执行并完成这将导致 IntentService 停止) - 我们 countDown() 我们在 onRequestSuccess ALSO 中的锁存器.

onDestroy:在这里我们停止我们的 SpinceManagers。

@Override
public void onDestroy() {
    super.onDestroy();
    LogUtils.LOGD(TAG, "onDestroy");
    shutDownSpiceManagers();
}

shutDownSpiceManagers

private void shutDownSpiceManagers() {
    if (aSpiceManager.isStarted()) {
        LogUtils.LOGD(TAG, "stopping aSpiceManager");
        aSpiceManager.shouldStop();
    }
    if (bSpiceManager.isStarted()) {
        LogUtils.LOGD(TAG, "stopping bSpiceManager");
        bSpiceManager.shouldStop();
     }
}

现在一切都应该好了:没有泄露的上下文,SpiceManagers 将在 onDestroy 中被杀死 并且仅在解决回调之后

【讨论】:

    【解决方案3】:

    如果您不希望完全同步执行,而只想按某种顺序顺序执行请求,您可以编写自己的简单类,当请求 A 成功或失败时只执行请求 B。像这样:https://github.com/Deepscorn/Shared/blob/master/app/src/main/java/com/gamelift/shared/request/base/RequestSequenceExecutor.java。 因此,代码将如下所示:

    sequenceExecutor.setRequest(new FirstRequest());
    sequenceExecutor.setOnSuccessListener(FirstRequest.class, new OnSuccessListener {
       public void onSuccess() {
         sequenceExecutor.setRequest(new SecondRequest());
       }
    };
    
    sequenceExecutor.setOnFaulListener(FirstRequest.class, new OnFailListener {
       public void onFail() {
         sequenceExecutor.setRequest(new OnFirstFailRequest());
       }
    };
    
    sequenceExecutor.setOnSuccessListener(SecondRequest.class, new OnSuccessListener {
       public void onSuccess() {
         notifyDone();
         return;
       }
    };
    
    sequenceExecutor.setDefaultOnFailListener(new OnFailListener {
       public void onFail(Exception e) {
         notifyDone();
         log(e);
         return;
       }
    };
    sequenceExecutor.execute() //starts execution
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-04
      • 1970-01-01
      • 2011-10-04
      • 2021-04-27
      • 2015-02-10
      • 2016-02-13
      相关资源
      最近更新 更多