14

我正在考虑对我的网络层进行改造。有什么方法可以判断特定的异步请求是否在任何给定时刻运行?

例如,我想知道请求是否正在运行,以便我可以在不同时间更新用户界面。我可以自己通过保持变量来跟踪状态来做到这一点,但想知道库中是否已经有一些东西。

4

2 回答 2

3

当需要一种方法来跟踪正在运行的请求时,我通常会这样做:

  • 首先,使用改造,只要您提出请求,您就可以执行以下操作:
  • 使用EventBus库将事件发布到您的活动或片段。现在,这可以在 Callback 的 onSuccess() 方法或相同的 onError() 方法中完成。
  • 在您的活动或片段的onEvent(EventClassName event)方法中,您可以简单地检查事件中的 [isRunning] 之类的变量,以确保如果事件仍在运行,则相应地更新 UI,如果没有,请执行您需要的操作分别做。
  • 请求完成后,显然 isRunning 将为 false,然后您可以按照用户的预期更新 UI。
  • 我在这里推荐 EventBus 只是因为它更容易将您的应用程序代码与它解耦;您可以发送不同的事件来通知活动您的请求的不同状态,然后以这种方式更新您的 UI。

你可以在这里找到 EventBus

我希望这有帮助!

于 2015-06-12T14:11:37.953 回答
2

在这种情况下,我个人最终做的是使用 Retrofit、Android Priority Jobqueue(来自 yigit 的 fork)和 Otto eventbus 运行示例。

public enum SingletonBus {
    INSTANCE;

    private Bus bus;

    private Handler handler = new Handler(Looper.getMainLooper());

    private SingletonBus() {
        this.bus = new Bus(ThreadEnforcer.ANY);
    }

    public <T> void postToSameThread(final T event) {
        bus.post(event);
    }

    public <T> void postToMainThread(final T event) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                bus.post(event);
            }
        });
    }

    public <T> void register(T subscriber) {
        bus.register(subscriber);
    }

    public <T> void unregister(T subscriber) {
        bus.unregister(subscriber);
    }
}

public interface Interactor {
    void injectWith(PresenterComponent presenterComponent);
}

public interface SendCertificateRequestInteractor
        extends Interactor {
    interface Listener {
        void onSuccessfulEvent(SuccessfulEvent e);

        void onFailureEvent(FailureEvent e);
    }

    class SuccessfulEvent
            extends EventResult<CertificateBO> {
        public SuccessfulEvent(CertificateBO certificateBO) {
            super(certificateBO);
        }
    }

    class FailureEvent
            extends EventResult<Throwable> {
        public FailureEvent(Throwable throwable) {
            super(throwable);
        }
    }

    void sendCertificateRequest(String username, String password);
}

注意Job这里:

public class SendCertificateRequestInteractorImpl
        implements SendCertificateRequestInteractor {
    private Presenter presenter;

    private boolean isInjected = false;

    @Inject
    public JobManager jobManager;

    public SendCertificateRequestInteractorImpl(Presenter presenter) {
        this.presenter = presenter;
    }

    @Override
    public void sendCertificateRequest(String username, String password) {
        if(!isInjected) {
            injectWith(presenter.getPresenterComponent());
            isInjected = true;
        }
        InteractorJob interactorJob = new InteractorJob(presenter, username, password);
        long jobId = jobManager.addJob(interactorJob); //this is where you can get your jobId for querying the status of the task if you want
    }

    @Override
    public void injectWith(PresenterComponent presenterComponent) {
        presenterComponent.inject(this);
    }

    public static class InteractorJob
            extends Job {
        private final static int PRIORITY = 1;
        private final static String TAG = InteractorJob.class.getSimpleName();

        private String username;
        private String password;

        @Inject
        public MyService myService;

        public InteractorJob(Presenter presenter, String username, String password) {
            super(new Params(PRIORITY).requireNetwork());
            presenter.getPresenterComponent().inject(this);
            this.username = username;
            this.password = password;
        }

        @Override
        public void onAdded() {
            // Job has been saved to disk.
            // This is a good place to dispatch a UI event to indicate the job will eventually run.
            // In this example, it would be good to update the UI with the newly posted tweet.
        }

        @Override
        public void onRun()
                throws Throwable {
            String certificate = myService.getCertificate(username, password);
            SingletonBus.INSTANCE.postToMainThread(new SuccessfulEvent(certificate));
        }

        @Override
        protected void onCancel() {
            // Job has exceeded retry attempts or shouldReRunOnThrowable() has returned false.
            Log.e(TAG, "Cancelled job.");
        }

        @Override
        protected boolean shouldReRunOnThrowable(Throwable throwable) {
            // An error occurred in onRun.
            // Return value determines whether this job should retry running (true) or abort (false).
            Log.e(TAG, "Failed to execute job.", throwable);
            SingletonBus.INSTANCE.postToMainThread(new FailureEvent(throwable));
            return false;
        }
    }
}

接着

@Subscribe
@Override
public void onSuccessfulEvent(SendCertificateRequestInteractor.SuccessfulEvent e) {
    String certificate = e.getResult();
    //do things
}

@Subscribe
@Override
public void onFailureEvent(SendCertificateRequestInteractor.FailureEvent e) {
    Throwable throwable = e.getResult(); 
    //handle error
}

更多关于android priority jobqueue 这里。

这样,从技术上讲,异步处理是指作业队列,而 Retrofit 本身使用的是同步接口。只要您不需要访问响应的标头,它就可以很好地工作。虽然公平地说,我还在跟踪作业是否使用布尔值而不是作业管理器和 id 运行。

另外,我还没有弄清楚如何在持久作业中正确使用依赖注入;我也不知道他们打算如何进行这项工作。当然,如果它使用应用程序范围的组件而不是提供的演示者范围的组件,它会起作用,但这无关紧要。

您可能需要根据自己的场景自定义此解决方案,并仅使用您实际需要的内容。

于 2015-06-12T14:33:41.323 回答