Rxjava使用,沒有理論只有實戰

  1. 線程切換->subscribeOnobserveOn

    Observable.just(1,2,3,4)
        .doOnNext {
            println("parade訂閱observeOn${Thread.currentThread().name}")
            //當subscribeOn在Schedulers.io()時  打印parade訂閱observeOnRxCachedThreadScheduler-1
            //當subscribeOn在AndroidSchedulers.mainThread()時  打印parade訂閱observeOnmain
        }
        .observeOn(AndroidSchedulers.mainThread())
        .doOnNext{
            println("parade第一次observeOn${Thread.currentThread().name}")//parade第一次observeOnmain
            println("parade value is $it")
        }
        .observeOn(Schedulers.io())
        .map {
            it * 3
            println("parade第二次observeOn${Thread.currentThread().name}")//parade第二次observeOnRxCachedThreadScheduler-2
        }
        .observeOn(AndroidSchedulers.mainThread())
        .doOnNext{
            println("parade第三次observeOn${Thread.currentThread().name}")//parade第三次observeOnmain
        }
        .subscribeOn(AndroidSchedulers.mainThread())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe()
    

    由實例代碼可以看出observeOn指定的是它之後的操作所在的線程,而subscribeOn指定產生訂閱時的線程,另外這樣做的好處是給用戶的的體驗是用戶感覺不到多次請求,也就是說如果要顯示加載Dialog,那麼從請求登錄開始顯示dialog到請求用戶信息結束dialog消失,所以用戶才感覺不到。從訂閱到整個請求鏈結束是一個完整的過程

  2. 操作符flatMap->用來把一個Observable轉成另外一個Observable

    1. 示例場景->登錄:先調用登錄接口,登錄成功後保存返回的token並接着調用獲取個人信息的接口

    2. 代碼實例

      ApiService.getUserApi().loginWithMobile(etLoginAccount.getText().toString()
              , EncryptUtils.encryptMD5ToString(etLoginPwd.getText().toString().trim()).toLowerCase()
              , etLoginCode.getText().toString().trim())
              .observeOn(AndroidSchedulers.mainThread())//這裏不可少,請求登錄用的是subscribeOn的io線程,登錄請求後切到主線程保存token或者刷新登錄驗證碼
              .doOnNext(new Consumer<StringModel>() {
                  @Override
                  public void accept(StringModel stringModel) throws Exception {
                      //登錄成功
                      app.getDataCenter().setToken(stringModel.getValue());
                      SPUtils.getInstance().put(SP_NAME_KEY, etLoginAccount.getText().toString().trim());
                      SPUtils.getInstance().put(SP_PWD_KEY,etLoginPwd.getText().toString().toString());
                  }
              })
              .doOnError(new Consumer<Throwable>() {
                  @Override
                  public void accept(Throwable throwable) throws Exception {
                      //登錄失敗,刷新二維碼,線程由上面的observeOn指定,是在主線程,因此可以更新UI
                      etLoginCode.setText("");
                      requestPhotoCode();
                  }
              })
              .observeOn(Schedulers.io())//處理完登錄接口後,再去調用請求個人信息接口
              .flatMap(new Function<StringModel, ObservableSource<UserModel>>() {
                  @Override
                  public ObservableSource<UserModel> apply(StringModel stringModel) throws Exception {
                      return ApiService.getUserApi().getUserInfo();
                  }
              })
              .subscribeOn(Schedulers.io())
              .observeOn(AndroidSchedulers.mainThread())
              .subscribe(new BaseObserver<UserModel>(mContext, true) {
                          @Override
                          public void onNext(UserModel userModel) {
                              //緩存用戶信息
                              app.getDataCenter().setUserModel(userModel);
                              jumpActivity(MainActivity.class);
                          }
                      });
      

      另外一個場景->上傳圖片,需要支持用戶同時上傳多張,但是接口只允許每次上傳一張

      Observable.fromIterable(parts)
              .flatMap(new Function<MultipartBody.Part, ObservableSource<Object>>() {
                  @Override
                  public ObservableSource<Object> apply(MultipartBody.Part part) throws Exception {
                      return ApiService.getProjectApi().uploadFile(part,Constant.orderAttach);
                  }
              })
              .subscribeOn(Schedulers.io())
              .observeOn(AndroidSchedulers.mainThread())
              .subscribe(new BaseObserver<Object>(mContext,true,"上傳中") {
                  @Override
                  public void onNext(Object o) {
                      TLog.e("上傳成功");
                      String attachUrl = (String) ((LinkedTreeMap) o).get("value");
                      if (selectAdapter.getData().size() == Constant.orderAttachMaxSelect) {
                          selectAdapter.getData().get(Constant.orderAttachMaxSelect - 1).setItemType(ImageVo.IMAGE);
                          selectAdapter.getData().get(Constant.orderAttachMaxSelect - 1).setImageUrl(attachUrl);
                          selectAdapter.notifyItemChanged(Constant.orderAttachMaxSelect - 1);
                      } else {
                          selectAdapter.addData(selectAdapter.getData().size() - 1, new ImageVo(ImageVo.IMAGE, attachUrl));
                      }
                      if (selectAdapter.getData().size() == Constant.orderAttachSpan + 1) {
                          new Handler().post(new Runnable() {
                              @Override
                              public void run() {
                                  nestScrollView.fullScroll(NestedScrollView.FOCUS_DOWN);//滾動到底部
                              }
                          });
                      }
                      attacheString = getAttachesString(selectAdapter.getData());
                      previewImages = getPreviewList(attachUrl);
                  }
              });
      
  3. 操作符merge->用來合併兩個沒有關聯的請求

    1. 示例場景,有些界面展示的數據需要通過兩個不相關的接口獲得,因此可以同時進行請求,如果不使用類似merge的合併操作符,那麼給用戶的直觀是進行了兩次請求(如果要顯示dialog,那兩個請求的dialog是獨立的),使用merge就可以使用一個dialog

    2. 示例代碼

      Observable<Feedback> feedbackInfoByAdviceId = NetWork.getOaService().getFeedbackInfoByAdviceId(themeId);
      Observable<AdviceTheme> adviceThemeById = NetWork.getOaService().getAdviceThemeById(themeId);
      Subscription subscription = Observable.merge(feedbackInfoByAdviceId,adviceThemeById)
              .subscribeOn(Schedulers.io())
              .observeOn(AndroidSchedulers.mainThread())
              .subscribe(new BaseSubscriber<Object>(FeedBackDetailActivity.this){
                  @Override
                  public void onNext(Object o) {
                      //因爲兩個Observable返回的數據類型不一致,所以這裏要用Object接收並進行類型判斷
                      if (o instanceof  Feedback){
                          tvFeedContent.setText(((Feedback)o).getContent());
                      }else if (o instanceof AdviceTheme){
                          AdviceTheme a = (AdviceTheme) o;
                          tvThemeTitle.setText(a.getTitle());
                          CommonUtils.parseHtml(tvThemeContent,a.getContent());
                      }
                  }
              });
      
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章