如何确定一个给定的请求是否正在运行?

14

我正在研究用于网络层的改装。有没有办法在任何时候告诉我一个特定的异步请求是否正在运行?例如,我想知道请求是否正在运行,以便我可以在不同的时间更新用户界面。我可以通过保留变量来跟踪状态来自己完成这个过程,但想知道库中是否已经有相关功能。


1
目前的Retrofit实现有一个接口回调,其中仅包括onSuccess和onFailure作为要实现的方法,据我所知。库本身并未提供任何用于确定给定请求是否正在运行的功能。这可能会成为一个不错的功能请求。 - user2511882
2个回答

3

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

  • 首先,使用Retrofit,一旦您发出请求,可以执行以下操作:
  • 使用EventBus库向活动或片段发布事件。现在,这可以在Callback的onSuccess()方法或同一方法的onError()方法中完成。
  • 在您的活动或片段的onEvent(EventClassName event)方法中,您可以简单地检查来自事件的[isRunning]变量,以确保如果事件仍在运行,则相应地更新UI,否则按需执行其他操作。
  • 当请求完成时,显然isRunning将为false,然后您可以像用户期望的那样更新UI。
  • 我在这里推荐EventBus,只是因为使用它更容易将应用程序代码解耦;您可以发送不同的事件,通知活动请求的不同状态,然后通过这种方式更新UI。

您可以在此处找到EventBus。

希望这有所帮助!


2
@Eenvinciblem,我正在使用事件总线和Retrofit,并使用公共静态字段来检查服务的状态。 - Muhammad Irfan

2

在这种情况下,我个人最终采用的方法是使用Retrofit、Android Priority Jobqueue(来自yigit的分支)和Otto事件总线运行示例。

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来跟踪作业是否正在运行。

此外,我还没有弄清楚如何正确使用持久性作业进行依赖注入;我也不知道他们打算如何使其工作。当然,如果它使用应用程序范围组件而不是提供的Presenter范围组件,那么它就可以工作,但这是无关紧要的。

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


1
哇,感谢您的慷慨赏金,先生。 - EpicPandaForce

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接