Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> RxJava/RxAndroid之快速入門3(轉)

RxJava/RxAndroid之快速入門3(轉)

編輯:關於Android編程

前言

最近諸事纏身,有點忙,終於抽出時間&&有興致寫第三了,有一股深深的罪惡感,廢話不多說,還是直接接上篇的活了,講一講一些比較常用的操作符吧。國際慣例,先丟兩個傳送門。
然後這篇講RxJava中強大的Scheduler調度器 ,就是因為它,RxJava才能極其簡便的在線程中切換,接著再講一講一些常用的操作符,比較簡單容易理解的操作符都在本篇羅列出來,以後可能不定時更新這篇文章,復雜的操作符後續分篇講。


Scheduler

在講常用操作符前,先看看Scheduler這個東西,名之為調度器,正因為有這個東西,讓RxJava可以從主線程和子線程之間輕松切換,各個Scheduler的具體使用效果看以下表解釋:

 

調度器類型 用途 Schedulers.computation(?) 用於計算任務,如事件循環或和回調處理,不要用於IO操作(IO操作請使用Schedulers.io());默認線程數等於處理器的數量 Schedulers.from(executor) 使用指定的Executor作為調度器 Schedulers.immediate(?) 在當前線程立即開始執行任務 Schedulers.io(?) 用於IO密集型任務,如異步阻塞IO操作,這個調度器的線程池會根據需要增長;對於普通的計算任務,請使用Schedulers.computation();Schedulers.io(?)默認是一個CachedThreadScheduler,很像一個有線程緩存的新線程調度器 Schedulers.newThread(?) 為每個任務創建一個新線程 Schedulers.trampoline(?) 當其它排隊的任務完成後,在當前線程排隊開始執行 AndroidSchedulers.mainThread() 此調度器為RxAndroid特有,顧名思義,運行在Android UI線程上

具體如何使用呢,比如從數據庫讀取數據更新到UI上,假設數據量很大,直接從主線程讀取數據,會造成UI卡頓,以前我們常用AnsyTask或者Handler去處理避免出現這類問題,個人認為手寫個AnsyTask還是挺麻煩的,但用RxJava就簡單多了,例如:

Observable.create(new Observable.OnSubscribe() {
    @Override
    public void call(Subscriber subscriber) {
        Data data = getData();//從數據庫獲取
        subscriber.onNext(data);
        subscriber.onCompleted();
    }})
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Action1() {
            @Override
            public void call(Data data) {

                    //更新ui
            }
        });

簡單粗暴的解釋一下,subscribeOn( )決定了發射數據在哪個調度器上執行,observeOn(AndroidSchedulers.mainThread())則指定數據接收發生在UI線程,簡直不要太方便。


常用操作符

  • Map:最常用且最實用的操作符之一,將對象轉換成另一個對象發射出去,應用范圍非常廣,如數據的轉換,數據的預處理等。
    例一:數據類型轉換,改變最終的接收的數據類型。假設傳入本地圖片路徑,根據路徑獲取圖片的Bitmap。

    Observable.just(filePath).map(new Func1() {
      @Override
      public Bitmap call(String path) {
    
           return getBitmapByPath(path);
      }}).subscribe(new Action1() {
       @Override
      public void call(Bitmap bitmap) {
    
              //獲取到bitmap,顯示
    }});

    例二:對數據進行預處理,最後得到理想型數據。實際開發過程中,從後台接口獲取到的數據也許不符合我們想要的,這時候可以在獲取過程中對得到的數據進行預處理(結合Retrofit)。

    Observable.just("12345678").map(new Func1() {
      @Override
      public String call(String s) {
          return s.substring(0,4);//只要前四位
      }})
    .subscribe(new Action1() {
      @Override
      public void call(String s) {
          Log.i("mytag",s);
      }});

    先說明一下,為了方便理解,所以寫的例子都比較簡單,不要以為明明可以簡單用if-else解決的事,沒必要用這種方式去寫,當你真正將這些操作符使用到數據處理中去的時候,你就會發現有多方便。

  • FlatMap:和Map很像但又有所區別,Map只是轉換發射的數據類型,而FlatMap可以將原始Observable轉換成另一個Observable。還是舉例說明吧。假設要打印全國所有學校的名稱,可以直接用Map:
    為了更清晰一點,先貼一下School類:

    public class School {
    
      private String name;
      private List studentList;
    
      public List getStudentList() {
          return studentList;
      }
      public void setStudentList(List studentList) {
          this.studentList = studentList;
      }
      public String getName() {
          return name;
      }
      public void setName(String name) {
          this.name = name;
      }
      public static class Student{
          private String name;
          public String getName() {
              return name;
          }
          public void setName(String name) {
              this.name = name;
          }
      }
    }

    接著用Map打印學校名稱:

    List schoolList = new ArrayList<>();
    Observable.from(schoolList).map(new Func1() {
      @Override
      public String call(School school) {
            return school.getName();
      }}).subscribe(new Action1() {
      @Override
      public void call(String schoolName) {
            Log.i("mytag",schoolName);
      }});

    再進一步,打印學校所有學生的姓名,先考慮用Map實現,將所有School對象直接轉成Student:

    Observable.from(schoolList).map(new Func1() {
      @Override
      public School.Student call(School school) {
          return school.getStudentList();
      }}).subscribe(new Action1() {
      @Override
      public void call(School.Student student) {
    
              Log.i("mytag",student.getName());
      }});

    看似可行,但事實上,這是一段錯誤的代碼,細心的人就會發現錯誤的地方

    @Override
    public School.Student call(School school) {
      return school.getStudentList();  //錯誤,Student 是一個對象,返回的卻是一個list
    }

    所以用Map是無法實現直接打印學校的所有學生名字的,因為Map是一對一的關系,無法將單一的School對象轉變成多個Student。前面說到,FlatMap可以改變原始Observable變成另外一個Observable,如果我們能利用from()操作符把school.getStudentList()變成另外一個Observable問題不就迎刃而解了嗎,這時候就該FlatMap上場了,來看看它是怎麼實現的:

    Observable.from(schoolList).flatMap(new Func1>() {
      @Override
      public Observable call(School school) {
    
          return Observable.from(school.getStudentList()); //關鍵,將學生列表以另外一個Observable發射出去
    
      }}).subscribe(new Action1() {
    
      @Override
      public void call(School.Student student) {
          Log.i("mytag",student.getName());
      }});

    Map和FlatMap在我看來就像孿生兄弟一樣,非常實用,實際開發中也我也經常使用,個人覺得要想上手RxJava,掌握這兩個操作符必不可少。

  • Buffer:緩存,可以設置緩存大小,緩存滿後,以list的方式將數據發送出去;例:

    Observable.just(1,2,3).buffer(2).subscribe(new Action1>() {
      @Override
      public void call(List list) {
          Log.i("mytag","size:"+list.size());
      }});

    運行打印結果如下:

    11-02 20:49:58.370 23392-23392/? I/mytag: size:2
    11-02 20:49:58.370 23392-23392/? I/mytag: size:1

    在開發當中,個人經常將Buffer和Map一起使用,常發生在從後台取完數據,對一個List中的數據進行預處理後,再用Buffer緩存後一起發送,保證最後數據接收還是一個List,如下:

    List schoolList = new ArrayList<>();
    Observable.from(schoolList).map(new Func1() {
      @Override
      public School call(School school) {
          school.setName("NB大學");  //將所有學校改名
          return school;
      }}).buffer(schoolList.size())  //緩存起來,最後一起發送
    .subscribe(new Action1>() {
      @Override
      public void call(List schools) {   
    }});
  • Take:發射前n項數據,還是用上面的例子,假設不要改所有學校的名稱了,就改前四個學校的名稱:
    Observable.from(schoolList).take(4).map(new Func1() {
      @Override
      public School call(School school) {
          school.setName("NB大學");
          return school;
      }}).buffer(4).subscribe(new Action1>() {
      @Override
      public void call(List schools) {
      }});
  • Distinct:去掉重復的項,比較好理解:
    Observable.just(1, 2, 1, 1, 2, 3)
          .distinct()
          .subscribe(new Action1() {
              @Override
              public void call(Integer item) {
                  System.out.println("Next: " + item);
              }
          });
    輸出
    Next: 1
    Next: 2
    Next: 3
  • Filter:過濾,通過謂詞判斷的項才會被發射,例如,發射小於4的數據:
    Observable.just(1, 2, 3, 4, 5)
          .filter(new Func1() {
              @Override
              public Boolean call(Integer item) {
                  return( item < 4 );
              }
          }).subscribe(new Action1() {
            @Override
            public void call(Integer item) {
                  System.out.println("Next: " + item);
        }});
    輸出:
    Next: 1
    Next: 2
    Next: 3

    這一篇就先講這麼多吧,重點掌握Map和FlatMap操作符,因為真的很實用、很實用、很實用,重要的事講三遍。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved