Rxjava基礎

  現在很多Android App的開發開始使用Rxjava,但是Rxjava以學習曲線陡峭著稱,入門有些困難。經過一段時間的學習和使用,這里來介紹一下我對Rxjava的理解。

  說到Rxjava首先需要了解的兩個東西,一個是Observable(被觀察者,事件源)和 Subscriber(觀察者,是 Observer的子類)。Observable發出一系列事件,Subscriber處理這些事件。首先來看一個基本的例子,我們如何創建并使用Observable。

Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("hello"); } }).subscribe(new Subscriber<String>(){ @Override public void onCompleted() {} @Override public void onError(Throwable e) { } @Override public void onNext(String s) { Log.d("rx-info", s); } });

  創建Observable的最基本的方法是通過Observable.create() 來進行,當有Subscriber通過Observable.subscribe() 方法進行訂閱之后Observable就會發射事件,注意必須要有訂閱者訂閱才會發射事件。發射的方式是通過調用 Observable中的 OnSubsribe 類型的成員來實現(每個Observable有一個final OnSubscribe<T> onSubscribe 成員,該成員是一個接口,后面詳細說),在 Onsubsribe類型成員中調用 call() 方法,注意,這個call方法的參數就是 Observable.subscribe() 方法傳入的 Subsriber實例。總的一句話就是在Obsubscribe 的 call方法中執行訂閱者(Subscriber)的三個方法 onNext(), onCompleted() 和 onError()。

  一開始就是一堆 Observable , Subscriber,subscribe() , OnSubscribe 估計看得頭暈,因此我們需要先來對這些東西有一個了解。這里只列出一個幫助理解的大概。

public class Observable<T> {final OnSubscribe<T> onSubscribe;protected Observable(OnSubscribe<T> f) {this.onSubscribe = f;}public final static <T> Observable<T> create(OnSubscribe<T> f) {return new Observable<T>(hook.onCreate(f));}public interface OnSubscribe<T> extends Action1<Subscriber<? super T>> {// cover for generics insanity}public final Subscription subscribe(Subscriber<? super T> subscriber) {return Observable.subscribe(subscriber, this);}public interface Operator<R, T> extends Func1<Subscriber<? super R>, Subscriber<? super T>> {// cover for generics insanity}
}
public interface Action1<T> extends Action {void call(T t);
}
public interface Subscription {void unsubscribe();boolean isUnsubscribed();
}
public interface Observer<T> {void onCompleted();void onError(Throwable e);void onNext(T t);
}public abstract class Subscriber<T> implements Observer<T>, Subscription {//...
}

  通過上面的代碼幫助理清楚 Observable, Observer, Subscriber, OnSubsriber, subscribe() 之間的關系。這里額外提一下 Observable.subscribe() 方法有多個重載:

Subscription    subscribe()
Subscription    subscribe(Action1<? super  T> onNext)
Subscription    subscribe(Action1<? super  T> onNext, Action1< java.lang .Throwable> onError)
Subscription    subscribe(Action1<? super  T> onNext, Action1< java.lang .Throwable> onError, Action0 onComplete)
Subscription    subscribe(Observer<? super  T> observer)
Subscription    subscribe(Subscriber<? super  T> subscriber)

  其它的ActionX 和 FuncX 請大家自行去查閱定義。

  介紹了基本的創建Observable和 Observable是怎么發射事件的之后,來介紹一下Rxjava的Operator和Operator的原理。

  Rxjava的Operator常見的有map, flatMap, concat, merge之類的。這里就不介紹Operator的使用了,介紹一下其原理。介紹原理還是來看源碼,以map為例。

  首先看一下使用map的例子:

Observable.create(new Observable.OnSubscribe<String>() {@Overridepublic void call(Subscriber<? super String> subscriber) {subscriber.onNext("hello");}
})
.map(new Func1<String, String>() {@Overridepublic String call(String s) {return s + "word";}
})
.subscribe(new Subscriber<String>() {@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable e) {}@Overridepublic void onNext(String s) {Log.d("info-rx", s);}
});

  繼續來看 map的定義:

    public final <R> Observable<R> map(Func1<? super T, ? extends R> func) {return lift(new OperatorMap<T, R>(func));}

  簡單說一下Func1,其中的T表示傳入的參數類型,R表示方法返回的參數類型。Operator的操作原理最核心的就是lift的實現。

    public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) {return new Observable<R>(new OnSubscribe<R>() {@Overridepublic void call(Subscriber<? super R> o) {try {Subscriber<? super T> st = hook.onLift(operator).call(o);try {// new Subscriber created and being subscribed with so 'onStart' itst.onStart();onSubscribe.call(st);} catch (Throwable e) {// localized capture of errors rather than it skipping all operators // and ending up in the try/catch of the subscribe method which then// prevents onErrorResumeNext and other similar approaches to error handlingExceptions.throwIfFatal(e);st.onError(e);}} catch (Throwable e) {Exceptions.throwIfFatal(e);// if the lift function failed all we can do is pass the error to the final Subscriber// as we don't have the operator available to uso.onError(e);}}});}

  lift方法看起來太過復雜,稍作簡化:

public final <R> Observable<R> lift(final Operator<? extends R, ? super T> operator) {return new Observable<R>(...);
}

  lift方法實際是產生一個新的 Observable。在map()調用之后,我們操作的就是新的Observable對象,我們可以把它取名為Observable$2,我們這里調用subscribe就是Observable$2.subscribe,繼續看到subscribe里,重要的幾個調用:

hook.onSubscribeStart(observable, observable.onSubscribe).call(subscriber);
return hook.onSubscribeReturn(subscriber);

  注意,這里的observable是Observable$2!!也就是說,這里的onSubscribe是,lift中定義的!!

  回過頭來看lift方法中創建新Observable的過程:

return new Observable<R>(new OnSubscribe<R>() {@Overridepublic void call(Subscriber<? super R> o) {try {Subscriber<? super T> st = hook.onLift(operator).call(o);try {// new Subscriber created and being subscribed with so 'onStart' itst.onStart();onSubscribe.call(st); //請注意我!! 這個onSubscribe是原始的OnSubScribe對象!!} catch (Throwable e) {// localized capture of errors rather than it skipping all operators // and ending up in the try/catch of the subscribe method which then// prevents onErrorResumeNext and other similar approaches to error handlingif (e instanceof OnErrorNotImplementedException) {throw (OnErrorNotImplementedException) e;}st.onError(e);}} catch (Throwable e) {if (e instanceof OnErrorNotImplementedException) {throw (OnErrorNotImplementedException) e;}// if the lift function failed all we can do is pass the error to the final Subscriber// as we don't have the operator available to uso.onError(e);}}
});

  一定一定要注意這段函數執行的上下文!,這段函數中的onSubscribe對象指向的是外部類,也就是第一個Observable的onSubScribe!而不是Observable$2中的onSubscribe,接下來看:

Subscriber<? super T> st = hook.onLift(operator).call(o);

  這行代碼,就是定義operator,生成一個經過operator操作過的Subscriber,看下OperatorMap這個類中的call方法: 

@Override
public Subscriber<? super T> call(final Subscriber<? super R> o) {return new Subscriber<T>(o) {@Overridepublic void onCompleted() {o.onCompleted();}@Overridepublic void onError(Throwable e) {o.onError(e);}@Overridepublic void onNext(T t) {try {o.onNext(transformer.call(t));} catch (Throwable e) {Exceptions.throwIfFatal(e);onError(OnErrorThrowable.addValueAsLastCause(e, t));}}};
}

  沒錯,對傳入的Subscriber做了一個代理,把轉換后的值傳入。這樣就生成了一個代理的Subscriber,最后我們最外層的OnSubscribe對象對我們代理的Subscriber進行了調用: 

 @Override
public void call(Subscriber<? super String> subscriber) {//此處的subscriber就是被map包裹(wrapper)后的對象。subscriber.onNext("hello");
}

  然后這個subscriber傳入到內部,鏈式的通知,最后通知到我們在subscribe函數中定義的對象。

  分析lift的原理,其實還是回到了一開始介紹的Observable必須要有訂閱者進行訂閱才能發射事件。lift方法會產生一個新的Observable,并且這個Observable位于原始Observable和后面的Subsriber之間,因此lift方法也需要提供一個新的Subscriber來使得新產生的Observable發射事件,這個新的Subsriber就是對事件鏈后方的Subscriber就行包裝做一個代理。

  詳細使用Rxjava可參見:

  1.?給 Android 開發者的 RxJava 詳解

  2.Rxjava使用基礎合集

?

轉載于:https://www.cnblogs.com/zhuyp1015/p/5215381.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/458296.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/458296.shtml
英文地址,請注明出處:http://en.pswp.cn/news/458296.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

『協議』XML-RPC 協議規格說明

為什么80%的碼農都做不了架構師&#xff1f;>>> 這篇文章提供所有實現XML-RPC協議所需要的內容。 一覽 XML-RPC是一個工作在因特網上的遠端程序調用&#xff08;Remote Procedure Calling&#xff09;協議。 XML-RPC消息是一個HTTP-POST請求&#xff08;Request&…

Qt之QLineEdit詳解(附源碼)

原博客地址&#xff1a;http://blog.csdn.net/liang19890820/article/details/52044639&#xff0c;感謝原作者總結和分享。 簡述 QLineEdit是一個單行文本輸入框。 QLineEdit允許用戶輸入和編輯單行純文本&#xff0c;提供了很多有用的編輯功能&#xff0c;包括&#xff1a;撤…

POJ 1323 Game Prediction#貪心

(&#xff5e;&#xffe3;▽&#xffe3;)&#xff5e;* //既然是求最少能勝幾次 //說明對方是要盡可能讓我輸 //但為了避免浪費&#xff0c;對方會用比我的牌大的牌中的最小pip的牌來擊敗我 #include<iostream> #include<cstdio> #include<cstring> #inclu…

qt學習之鍵盤事件( keyPressEvent)

//最近一直忙于做驅動&#xff0c;對底層東西很是好奇&#xff0c;好奇鍵盤是 怎么區分每個鍵值的&#xff0c;又是怎么響應的&#xff01;因此&#xff0c;就有了下面這些代碼//環境windows 工具qt 語言c//在主窗體類中聲明鍵盤響應函數 void keyPressEvent(QKeyEvent * event…

C#json數據的序列化和反序列化(將數據轉換為對象或對象集合)

引用 System.Runtime.Serialization.Json 轉載于:https://www.cnblogs.com/a849788087/p/5645828.html

位圖(bmp)文件格式分析

from&#xff1a;https://blog.csdn.net/qingchuwudi/article/details/25785307 位圖(bmp)文件格式分析 作者&#xff1a;深藍&#xff08;由博主分享&#xff09; 一、什么是位圖 計算機能以位圖和矢量圖格式顯示圖像。 1、位圖(Bitmap)&#xff1a; 圖像又稱點陣圖或光…

匯付 支付,痛苦的接入過程

有文檔&#xff0c;但是&#xff0c;寫文檔的人明白&#xff0c;看文檔的人很有難度。 沒有SDK&#xff0c;要自已寫。 然后&#xff0c;錢的流入流出都必須經過虛擬錢包&#xff0c;提現還要綁取現卡&#xff0c;這個我也能理解&#xff0c;不能理解的是&#xff0c;訂單退款&…

隨筆分類 - HALCON學習例程中文詳解

from: https://www.cnblogs.com/chita/category/563492.html隨筆分類 - HALCON學習例程中文詳解HALCON學習例程中文詳解跟我學機器視覺-HALCON學習例程中文詳解-測量圓環腳寬間距摘要: 跟我學機器視覺-HALCON學習例程中文詳解-測量圓環腳寬間距* This example program demonstr…

WinCE6 如何去掉控制面板中的應用?

在WINCE600/PUBLIC/WCESHELLFE/OAK/FILES/wceshellfe.bib把對應的cpl 干掉例如區域設置 好像是2個 ; CESYSGEN IF WCESHELLFE_MODULES_INTLPintlp.cpl $(_FLATRELEASEDIR)/intlp.cpl NK SH ; CESYSGEN ENDIF ; CESYSGEN IF WCESHELLFE_MODULES_INTLLintll.cpl $(_FLATRELEASEDI…

軟件自動更新解決方案及QT實現

from&#xff1a;https://blog.csdn.net/hulinhulin/article/details/46839107軟件自動更新解決放案及QT實現...11 文件的版本控制-XML.22 更新程序的實現...22.1 界面設置...22.2 程序功能...32.2.1 下載網絡數據...32.2.2 XML文件的分析...62.2.3 下載XML文件的DownLoadXML函…

java 基本功 —— 內存相關

2019獨角獸企業重金招聘Python工程師標準>>> 首先我們來說說內存&#xff0c;因為從內存的角度來出發來分析一些變量&#xff0c;引用或者對象的生命周期會更好理解一些。 java是一門編程語言&#xff0c;他跟C有什么不同呢&#xff1f;本質上&#xff0c;他們都是一…

DOM事件處理有三個階段

DOM事件處理有三個階段&#xff1a; 捕捉階段&#xff08;capture phase&#xff09;&#xff1a;從最上層元素&#xff0c;直到最下層&#xff08;你點擊的那個target&#xff09;元素。路過的所有節點都可以捕捉到該事件。命中階段&#xff08;target phase&#xff09;&…

客戶端程序自動更新(升級)的方式

from&#xff1a;https://blog.csdn.net/woaitingting1985/article/details/72954652一、C/S自動更新原理C/S程序自動升級是一個很重要的功能&#xff0c;原理其實很簡單&#xff0c;一般包含兩個程序一個是主程序&#xff0c;也就是除了升級功能以外的程序&#xff0c;另一個就…

怎么用源程序把ChemDraw結構復制到Word文檔

在學習化學過程中&#xff0c;不可避免的會接觸到各種化學結構。這個時候就需要通過繪制化學結構來進行這方面的學習和傳播。ChemDraw Professional 15就可以輔助完成這方面的工作。很多的用戶朋友會通過選中后復制粘貼可以將ChemDraw結構復制到Word文檔中&#xff0c;但這只是…

網絡流(最大流) HDU 1565 方格取數(1) HDU 1569 方格取數(2)

HDU 1565 方格取數(1)給你一個n*n的格子的棋盤&#xff0c;每個格子里面有一個非負數。從中取出若干個數&#xff0c;使得任意的兩個數所在的格子沒有公共邊&#xff0c;就是說所取的數所在的2個格子不能相鄰&#xff0c;并且取出的數的和最大。 Input 包括多個測試實例&#…

python學習 第一篇 基礎

上周報名了reboot python 課程&#xff0c;終于下決心要把python 搞好了&#xff0c;希望自己能堅持下來&#xff0c;并得到自己想要的成績#coding:utf-8 #呵呵 #print hello world #xhello world #print x #xraw_input(hello world) #print x #int #print 23 #print 12*3 #pri…

QT串口編程的相關類(QSerialPortInfo)

QT Serial Port相關的類只有兩個QSerialPortInfo(#include<QSerialPortInfo>) 和QserialPort(#include<QSerialPort>) 先來介紹QSerialPortInfo 1&#xff1a;QSerialPortInfo(#include<QSerialPortInfo>) 該類是一個串口的輔助類類&#xff0c;提供主要是提…

用jquery寫一個屬于自己的音樂播放器

看到一個用css3實現的CD的動畫&#xff0c;演示在這兒http://codepen.io/_kieran/pen/QNRmep 突然那我就想說給自己做一個音樂播放器吧&#xff0c;說做就做。演示在https://echolsx.github.io/music/ Github傳送門&#xff1a;https://github.com/EchoLsx/music 主要代碼&…

四年一閏 隨筆

今天日子比較特殊&#xff0c;碰到閏年的2月29日。好久沒有記錄隨筆了&#xff0c;今天隨便記上幾筆吧 1、上家公司居然沒幫我交社保&#xff0c;一整年了&#xff0c;發工資時還照扣社保的錢。。。現在說會補差額給我&#xff0c;算下來一年XXXX&#xff0c;也只是個數字&…

Qt 串口類QSerialPort 使用筆記

Qt 串口類QSerialPort 使用筆記雖然現在大多數的家用PC機上已經不提供RS232接口了。但是由于RS232串口操作簡單、通訊可靠&#xff0c;在工業領域中仍然有大量的應用。Qt以前的版本中&#xff0c;沒有提供官方的對RS232串口的支持&#xff0c;編寫串口程序很不方便。現在好了&a…