RxJava Android方向更改和网络请求

时间:2018-07-04 08:27:56

标签: android networking rx-java2 orientation-changes

我是RxJava的新手,我需要将其集成到现有项目中。我需要重构现有代码,为网络(套接字IO)添加Observables

当前,当发出网络请求(客户端->服务器)时,回调(接口)被添加到HashMap中,并且一旦请求完成,它将把数据传递回调用者:

// Singleton
public class API {

   public void checkTicket(String ticketId, final String networkRequestId, Callback callback) {
      // Add the callback to the hashmap
      registerCallback(networkRequestId, callback);

      JSONObject json = RequestFactory.createTicketCheckerRequest(ticketId);

      // Make the network request
      getSocket().checkTicket(json, new Callback() {
          @Override
          public void onRequestDone(Response response) {

              // Retrieve the callback
              callback = getCallback(networkRequestId);

              // Don't keep reference, remove from hashmap
              unsubscribeCallback(networkRequestId);

              // Check if it's unsuccessful and build the corresponding error response
              if (!response.isSuccess()) {
                  // build custom error response
                  response = ResponseFactory.buildError(response);
              }

              // Deliver response from server
              callback.onRequestDone(response);
          }
      });
  }

}

可以从ActivitiesFragments进行调用:

private void checkTicket() {
   String ticketId = editText.getText().toString();

   API.getInstance().checkTicket(ticketId, REQUEST_ID_CHECK_TICKET, new Callback() {
      @Override
      protected void onRequestDone(Response response) {
         textView.setText(response.getData());
      }
   });
}

@Override
public void onDestroy() {
   super.onDestroy();

   // Removes callback from HashMap in case of the UI is destroyed before the arrives
   API.getInstance().unsubscribe(REQUEST_ID_CHECK_TICKET);
}

上面的代码有效,但是它确实与UI的生命周期紧密相关,有时会导致内存泄漏,因为没有调用onDestroy()(如果您在活动之间导航,并且A​​ndroid OS杀死了堆栈中的“已暂停”活动) ),或者因为匿名内部类(回调)持有对UI的引用,并且从现在开始我需要支持方向更改

这是我使用RxJava实现的代码:

API

public Observable<Response> checkTicket(String ticketId) {
   return Observable.create(subscriber -> {
      JSONObject json = RequestFactory.createTicketCheckerRequest(ticketId);

      // Make the network request
      getSocket().checkTicket(json, new Callback() {
         @Override
         public void onRequestDone(Response response) {
            subscriber.onNext(response);
            subscriber.onComplete();
         }
      });
   });
}

这是从用户界面调用的方式:

private CompositeDisposable mDisposables = new CompositeDisposable();

private void checkTicket() {
   //////

   Disposable disposable = API.getInstance().checkTicket(ticketId)
      .observeOn(AndroidSchedulers.mainThread())
      .subscribeOn(Schedulers.io())
      .subscribe(result -> {
         textView.setText(result.getData());
      });

   mDisposables.add(disposable);
}

@Override
public void onStop() {
   super.onStop();

   if (!mDisposables.isDisposed()) {
      mDisposables.dispose();
   }
}

以上RxJava正常工作,但是,如果发生方向更改,则由于Observer尚未订阅,因此不会返回数据。

  1. 以上实现是否正确?
  2. 如何在不执行请求的情况下进行订阅?订阅并等待数据更改。

另一种选择是EventBus,但这只是计划B。EventBus完全符合我的要求,订阅并等待数据更改,但是我想逐出样板。

我已经通过使用Fragment的{​​{1}}阅读了其他文章,但是如果我需要从setRetainInstance(true)中使用它,该怎么办?如果我不想保留Activity的状态怎么办? 人们建议使用FragmentMVVM体系结构,但我没有时间重构整个项目。

3 个答案:

答案 0 :(得分:2)

我建议您使用MVVM。使用您提供的代码,这并不难。这是一个示例代码,看起来像

您的ModelView


import subprocess

def your_view(request):

    subprocess.call('your_script.sh')

您的活动

public class MyViewModel extends ViewModel {
    private CompositeDisposable mDisposables = new CompositeDisposable();
    private MutableLiveData<Response> response;

    public LiveData<Response> getResponse() {
        if (response == null) {
            response = new MutableLiveData<Response>();
            loadData();
        }
        return response;
    }

    private void loadData() {
        Disposable disposable = API.getInstance().checkTicket(ticketId)
          .observeOn(AndroidSchedulers.mainThread())
          .subscribeOn(Schedulers.io())
          .subscribe(result -> {
             response.postValue(result.getData());
          });

       mDisposables.add(disposable);
    }

    void onCleared()
    {
        super.onCleared();
        mDisposables.clear(); //no more leaks. It takes care of lifecycle for you
    }
}

答案 1 :(得分:1)

如果您不想处理配置更改,也不希望从可观察对象缓存数据,则可以使用BehaviorSubjects和一个热可观察对象。这将使您获得可观察到的最新出版物。

除此之外,我建议您使用体系结构组件中的ViewModel。它将允许您创建绑定到活动但不受生命周期影响的组件(显然,终止除外)。令人惊讶的是,ViewModelProviders被实现为带有setRetainInstance(true)的片段。您不必完全重构整个应用程序。只需在配置更改期间移动要保留的内容即可。

答案 2 :(得分:0)

您需要考虑网络请求的逻辑范围,这与是否使用RxJava完全分开。诸如网络请求之类的后台任务需要由具有适当生命周期的Android组件(ApplicationActivity等)拥有。使活动范围的后台任务在配置更改后仍然有效的通常方法是将它们托管在retained fragment中。如果您使用的是RxJava,您仍然会这样做。

  

Android OS杀死堆栈中的“暂停”活动

除非在Android 8或更高版本中进行了某些更改,否则不会发生这种情况。该文档建议框架可以销毁后台程序中的单个活动,但目前仅在后台执行时销毁整个任务。您的应用程序只有在启用了“不要继续进行活动”开发人员选项的情况下,才是正确且面向未来的。