如何优雅地取消Retrofit请求?

5,651 阅读1分钟

在实际开发中,页面关闭,取消请求是很常见的需求,这里分享一种简单的实现方法。 我的思路是把网络请求和上下文的生命周期绑定。这里用用到了Rxjava的Subject,Subject 既是 Observable 又是 Observer(Subscriber)。既可以发消息也可以接收消息。

我首先定义了几个枚举,对应上下文的生命周期。

public enum ActivityLifeCycleEvent {
    CREATE,START,RESUME,PAUSE,STOP,DESTROY
}

Fragment为例,在BaseFragment中,相应的生命周期回调中发射消息。


import rx.subjects.PublishSubject;

public abstract class BaseFragment extends Fragment {

    protected final PublishSubject<ActivityLifeCycleEvent> lifecycleSubject = PublishSubject.create();



    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onActivityCreated(savedInstanceState);
    }

    @Override
    public void onPause() {
        super.onPause();
        lifecycleSubject.onNext(ActivityLifeCycleEvent.PAUSE);
    }

    @Override
    public void onStop() {
        super.onStop();
        lifecycleSubject.onNext(ActivityLifeCycleEvent.STOP);
    }


    @Override
    public void onResume() {
        super.onResume();
        lifecycleSubject.onNext(ActivityLifeCycleEvent.RESUME);
    }


    @Override
    public void onDestroy() {
        super.onDestroy();
        lifecycleSubject.onNext(ActivityLifeCycleEvent.DESTROY);
    }

}

一般情况下我们会使用Retrofit+Rxjava来进行网络请求,比如像下面这样:

@Multipart
@POST(Urls.TIMER_GETUSERDETAIL_RX)
Observable<Results<User>> getUser(@PartMap Map<String, RequestBody> map);

具体请求的时候可能是下面这样

ApiService.instancce()
  .getUser(p.build())
  .takeUntil(bindLifeCycle(lifecycleSubject,ActivityLifeCycleEvent.DESTROY))
  .subscribe({
      ……
  })

注意:下面这句话

.takeUntil(RxUtils.bindLifeCycle(lifecycleSubject, ActivityLifeCycleEvent.DESTROY))

takeUntil一旦响应是成功它将自动终止源Observable于是停止向后端发送数据。如果不是则继续发送请求。这里如果收到ActivityLifeCycleEvent.DESTROY消息,就会停止向后端发送数据。

 public static Observable<ActivityLifeCycleEvent> bindLifeCycle(PublishSubject<ActivityLifeCycleEvent> lifecycleSubject, ActivityLifeCycleEvent bindEvent) {
        return  lifecycleSubject.takeFirst(activityLifeCycleEvent -> activityLifeCycleEvent.equals(bindEvent));
    }

嗯,就这么多。下面就是愉快地使用吧~

本方法只是取消了接受网络数据之后的后续操作,并不是真正停止了当前的请求哦~