Rxjava梳理(2)--Transform,Operator

关于Rxjava的第二篇文章来了,前几天由于我情绪不佳暂时中断几天。今天终于恢复心情,开始继续自己梳理工作。

在之前的文章《Rxjava梳理(1)--Observable,Observer,subscribe》里讲到了Observable,observer,subscribe这些Rxjava中的基本概念。本篇文章想梳理一下Rxjava里面最有用以及最难以理解的一个特性:"变换(Transform)"。有人会觉得Rxjava很好用,又有些人会觉得Rxjava很难理解,绝大多数正是因为Rxjava的变换特性

用例子来说明吧:假设有一个方法是要把一个字符串显示在文本控件上,一般方法如下

  public void displayText(String text){
   textView.setText(text);
  }
   

而如果运用上一篇文章所讲的,就应该这样写

    public void displayText(String text){
      Observable.just(text).subscribe( new Action1<String>(){
         public void call(String s){
            textView.setText(s);
        }


});  
 
    }

这个时候如果有这样的一个需求,需要对该字符串在显示之前,先做一些处理转换成新的字符串再打印,应该如何做呢?这时候我们可以这样做

   public void displayText(String text){
     String newText = convertToNewText(text);
    Observable.just(newText).subscribe( new Action1<String>(){
         public void call(String s){
            textView.setText(s);
        }
});  
  }

这样做有一个问题就是如果我们是从第三方库里得到的是封装了该字符串对象的Observable对象应该如何做呢?当然这样,我们也可以这样做

    public void displayText(String text){
     Observable.just(text).subscribe( new Action1<String>(){
         public void call(String s){
            String newText = convertToNewText(s);
            textView.setText(newText);
        }
});  
   }

这种方法也有一个问题,就是 call方法里的方法明显应该放在主线程里,如果convertToNewText()方法是一个非常耗时的方法的话就会对应用程序的性能造成很大的影响,所以尽量保证call方法里的处理逻辑简洁是很重要的事情,这就使得我们可以尝试map()方法来尝试解决这个问题

    public void displayText(String text){
      Observable.just(text).map(new Func1<String,String>(){
           
          public String call(String text){
             return convertToNewText(text);   
           }

      }).subscribe( new Action1<String>(){
         public void call(String s){
            textView.setText(s);
        }
        });

    }

通过这个例子可以看出来,map方法通过Func1这个对象把一个字符串转换为另一个字符串,并在订阅的方法里显示出这个改变了的字符串,和之前的方法比,是不是逻辑更加清晰些了呢?当然,Func1对象不仅仅可以转换成相同类型的对象,还可以把一种类型的对象转换成其他类型的对象,比如说上面的例子,如果我们想显示该字符串的长度呢?

 public void displayLengthOfText(String text){
  Observable.just(text).map(new Func1<String,Integer>(){
    public Integer call(String text){
     return text.length(); 
  }
}).map(new Func1<Integer,String>(){
  public String call(int length){
   return Integer.toString(length); 
}
}).subscribe(new Action1<Integer>(){
   public void call(String length){
         textView.setText(length);
  }
})
}

可见这种方式把每一种转换都单独放到了一个方法里,让逻辑更加清晰。
如果情况更加复杂了呢,比如,我得到一个字母列表比如{"a","b","c"}。这个列表里面的元素又需要到单词表里搜出以该字母为首字母的单词列表,比如以a为首字母的列表就会有{"cat","career","chat"...},而我订阅的方法就需要把这些单词打印出来,这样一个需求如何实现呢?我们可以这样来做

public void displayWord(List<String> letters){
   Observable.from(letters).map(new Func1<String,List<String>>(){
           public List<String> call(String letter){
     List<String> words = getWordsByLetter(letter);
               return words
   }  
   }).subscribe(new Action1<List<String>>(){
         public void call(List<String> words){
             for(String word:words){
                System.out.println(word);
             }
        }
});
}
     

这种实现的问题就会把过多的代码都放到了Action1类的方法里,不利于对每一个字符串对象进行变换处理。这时候flatMap()方法被提了出来

   public void displayWord(List<String> letters){
     Observable.from(letters).flatMap(new Func1<String,Observable<String>>(){
            public Observable<String> call(String letter){
          Observable<String> words= Observable.from(getWordsByLetter(letter));
           return words;
  }      
} ).subscribe(new Action1<String>(){
      public void call(String word){
         
            System.out.println(word);
     }
});
  }

从上面的例子可以看到,flatMap里的Func1对象里的call()方法返回的是Observable对象.flatMap()方法的原理如下:

  1. flatMap()方法返回一个大的Observable对象
  2. call()方法并不是返回Observable对象给步骤1的大Observable对象,而是把它的事件(即String对象)传给了大的Observable对象
  3. 这样大的Observable对象汇聚了所有的匿名类中生成的Observable对象里的事件,统一发给了Subscriber对象。

要了解这些转换的原理的话,就需要了解lift(Operator)方法,该方法的一些重要的代码如下:

  public<R> Observable<R> lift(Operator<? extends R,? super T> oprator){
          return Observable.create(new OnSubscibe<R>(){

public void call(Subscriber subscriber){

   Subscriber newSubscriber = operator.call(subscriber);
  newSubscriber.onStart();
  onSubscribe.call(newSubscriber);
}

});
   }

需要解释一下lift() 方法的原理:

  1. lift()方法生成了一个新的Observable对象,和原来的Observable对象并存。
  2. 当lift()方法生成的新的Observable对象调用subscribe()方法的时候,该Obsersable的OnSubscriber对象的call()方法被调用,就是上面代码块中的方法。
  3. call方法里首先用了operator.call()方法用我们调用的Subscriber对象生成了一个新的Subscriber对象,并且把两者连接起来
  4. 后面的onSubscribe方法是原始的Observable对象里面的OnSubscribe对象,通过call方法调用了新的Subscriber对象里的方法,实际上也就间接调用了原来的Subscriber对象里的方法。

这一篇文章的内容相对比较抽象和晦涩,我可能未必讲清楚了,只是梳理了一下自己的思路,欢迎大家和我交流,共同成长。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容