? ? ? ?今天來給大家介紹當下比較流行的響應式函數(shù)編程艰管,以下是整理和搜集整理的關于Rx的一些資料彬呻。響應式函數(shù)編程
確實是一種對新入行的人來說是一種新穎而又高效的編程方式俭令。但是不建議新手采用這種方法進行立項驻粟,其中的牽扯到
觀察者模式友扰,訂閱者模式還得等看過一定的算法和設計模式之后役电,才能理解的恰如其分赚爵,使用起來也可以得心應手,不過
在學習基礎的時候法瑟,理解和練習一些小的demo冀膝,對學習設計模式還是很有幫追的。今天介紹的實際上只有只有一種霎挟,就是
RxJava與RxAndroid,當然現(xiàn)在也有很多框架窝剖,像上幾篇提高的網絡請求OkGo都支持Rx的擴展,基于此給大家分享一下酥夭。
5枯芬、響應式函數(shù)編程Rx(Reactive Extensions)
主頁:https://github.com/ReactiveX/RxJava
中文資料:(這是一些大神分享一些學習的資料,參照的學習采郎,確實英語有點尷尬了)
? ? ? ? ? ? ? https://github.com/lzyzsd/Awesome-RxJava
? ? ? ? ? ? ? https://www.zhihu.com/question/35511144
含義:
? ? ?RxJava 的異步實現(xiàn)千所,是通過一種擴展的觀察者模式來實現(xiàn)的。
? ? ?觀察者模式面向的需求是:A 對象(觀察者)對 B 對象(被觀察者)的某種變化高度敏感蒜埋,需要在 B 變化的一瞬間做出反應
用途:
? ? 異步操作
? ? 在程序邏輯異常復雜的情況下,仍然可以讓代碼的邏輯保持簡潔
配置: 添加依賴:
compile'io.reactivex.rxjava2:rxandroid:2.0.1'
compile'io.reactivex.rxjava2:rxjava:2.1.0'
如果結合Retrofit使用,需要添加以下依賴
compile 'com.squareup.retrofit2:retrofit:2.0.1'
compile 'com.squareup.retrofit2:converter-gson:2.0.1'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.1'
基本的理解和用法
1.被觀察者: Observable
? ? ?作用: 決定什么時候觸發(fā)事件以及觸發(fā)怎樣的事件
創(chuàng)建方法:
? ? Observable.just(T...) 參數(shù)為單個的
? ? Observable.from(T[]) / Observable.from(Iterable)??參數(shù)為數(shù)組或Iterable
2.觀察者: Observer
? ?作用: 當事件觸發(fā)的時候將有怎樣的行為
? ?實現(xiàn)類有Observer / Subscriber
3.訂閱: subscribe
? ?作用: 把Observable和Observer關聯(lián)起來
? ?方法:
? ?observable.subscribe(observer);
? ?observable.subscribe(subscriber);
4.事件
? ?onNext():普通事件
? ?onCompleted():事件隊列完結
? onError(): 事件隊列異常
? 需要注意的是onCompleted()和onError()是互斥的.調用了其中一個就不應該觸發(fā)另一個.
5.測試程序
?? ? ?現(xiàn)有一個數(shù)組 String[] arr ={"afdsa", "bfdsa", "cfda"}, 把其中以字母"a"開頭的字符串找出來并加上"from Alpha",最后打印出新的字符串的長度
? ?private void simpleDemo() {
? ? ? String[] arr = {"afdsa", "bfdsa", "cfda"};
? ? ? Observable
? ? ? ? ? ? ? ? ? ? ? .from(arr)
? ? ? ? ? ? ? ? ? ? ? .filter(new Func1() {
? ? ? ? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? ? ? ? public Boolean call(String s) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?return s.startsWith("a");
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ?})
? ? ? ? ? ? ? ? ? ? ?.map(new Func1() {
? ? ? ? ? ? ? ? ? ? ?@Override
? ? ? ? ? ? ? ? ? ? ?public String call(String s) {
? ? ? ? ? ? ? ? ? ? ? ? ? return s + " from Alpha";
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ?})
? ? ? ? ? ? ? ? ? ? ?.subscribe(new Action1() {
? ? ? ? ? ? ? ? ? ? ?@Override
? ? ? ? ? ? ? ? ? ? ?public void call(String s) {
? ? ? ? ? ? ? ? ? ? ? ? ? System.out.println("Rxjava:" + s.length());
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ?});
? ? ? ? ? ? ? ? ? ?for (int i = 0; i < arr.length; i++) {
? ? ? ? ? ? ? ? ? ? ? ?String temp = arr[i];
? ? ? ? ? ? ? ? ? ? ? ?if (temp.startsWith("a")) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? temp += " from Alpha";
? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.println("Normal:" + temp.length());
? ? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? }
? ? ?由指定的一個 drawable 文件 id 取得圖片淫痰,并顯示在 ImageView 中,并在出現(xiàn)異常的時候打印 Toast 報錯
? ? ?private void simpleDemo() {
? ? ? ? ? ? ? ? ?final int drawID = R.mipmap.ic_launcher;
? ? ? ? ? ? ? ? ?Observable
? ? ? ? ? ? ? ? ?.create(new Observable.OnSubscribe() {
? ? ? ? ? ? ? ? ?@Override
? ? ? ? ? ? ? ? ?public void call(Subscriber subscriber) {
? ? ? ? ? ? ? ? ?Drawable drawable = getResources().getDrawable(drawID);
? ? ? ? ? ? ? ? ?subscriber.onNext(drawable);
? ? ? ? ? ? ? ? ?subscriber.onCompleted();
? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? })
? ? ? ? ? ? ? ?.subscribe(new Observer() {
? ? ? ? ? ? ? ?@Override
? ? ? ? ? ? ? ?public void onCompleted() {
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? public void onError(Throwable e) {
? ? ? ? ? ? ? ? ? ? Toast.makeText(MainActivity.this, "Error", Toast.LENGTH_SHORT).show();
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ?public void onNext(Drawable drawable) {
? ? ? ? ? ? ? ? ? ? imageView.setImageDrawable(drawable);
? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ?});
? ? ? }
6.Scheduler(調度器)
? ? 作用: 控制線程.指定某一段代碼在那個線程里運行.
? ? 在不指定線程的情況下整份, RxJava 遵循的是線程不變的原則待错,即:在哪個線程調用 subscribe(),就在哪個線程生產事件烈评;在哪個線程生產事件火俄,就在哪個線程消費事件。如果需要切換線程讲冠,就需要用到 Scheduler (調度器)瓜客。
? ?在RxJava 中,Scheduler ——調度器竿开,相當于線程控制器谱仪,RxJava 通過它來指定每一段代碼應該運行在什么樣的線程。RxJava 已經內置了幾個 Scheduler 否彩,它們已經適合大多數(shù)的使用場景:
? ?內置的Scheduler:
? ?Schedulers.immediate(): 直接在當前線程運行疯攒,相當于不指定線程。這是默認的 Scheduler列荔。
? ?Schedulers.newThread(): 總是啟用新線程敬尺,并在新線程執(zhí)行操作枚尼。
? ?Schedulers.io(): I/O 操作(讀寫文件、讀寫數(shù)據(jù)庫砂吞、網絡信息交互等)所使用的 Scheduler署恍。行為模式和 newThread() 差不多,區(qū)別在于 io() 的內部實現(xiàn)是是用一個無數(shù)量上限的線程池呜舒,可以重用空閑的線程锭汛,因此多數(shù)情況下 io() 比 newThread() 更有效率笨奠。不要把計算工作放在 io() 中袭蝗,可以避免創(chuàng)建不必要的線程。
? ?Schedulers.computation(): 計算所使用的 Scheduler般婆。這個計算指的是 CPU 密集型計算到腥,即不會被 I/O 等操作限制性能的操作,例如圖形的計算蔚袍。這個 Scheduler 使用的固定的線程池乡范,大小為 CPU 核數(shù)。不要把 I/O 操作放在 computation() 中啤咽,否則 I/O 操作的等待時間會浪費 CPU晋辆。
? ?AndroidSchedulers.mainThread(): Android專用,它指定的操作將在 Android 主線程運行。
? 指定線程的方法:
? Observable.subscribeOn():指定 subscribe() 所發(fā)生的線程宇整,即 Observable.OnSubscribe 被激活時所處的線程瓶佳。或者叫做事件產生的線程
? Observable.observeOn():指定 Subscriber 所運行在的線程鳞青“运牵或者叫做事件消費的線程。
7.數(shù)據(jù)變換
? 作用: 就是將事件序列中的對象或整個序列進行加工處理臂拓,轉換成不同的事件或事件序列
? ?Observable.map:??一對一的轉換
? private void simpleDemo() {
? ? ? Observable
? ? ? ? ? ? ? ? ? ? ? ?.just(R.mipmap.ic_launcher)
? ? ? ? ? ? ? ? ? ? ? ?.map(new Func1() {
? ? ? ? ? ? ? ? ? ? ? ?@Override
? ? ? ? ? ? ? ? ? ? ? ?public Drawable call(Integer integer) {
? ? ? ? ? ? ? ? ? ? ? ? ? ?return getResources().getDrawable(integer);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? })
? ? ? ? ? ? ? ? ? ? ? .subscribe(new Action1() {
? ? ? ? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? ? ? ? public void call(Drawable drawable) {
? ? ? ? ? ? ? ? ? ? ? ? ? ?imageView.setImageDrawable(drawable);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? });
? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? Observable.flatMap: 一對多的轉換
? ? ? ? ? public class Course {
? ? ? ? ? ? ? ?private String name;
? ? ? ? ? ? ? ?private int id;
? ? ? ? ? ? ? ?public Course(String name, int id) {
? ? ? ? ? ? ? ? ? ?this.name = name;
? ? ? ? ? ? ? ? ? ?this.id = id;
? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ?public String getName() {
? ? ? ? ? ? ? ? ? ?return name;
? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ?public void setName(String name) {
? ? ? ? ? ? ? ? ? ?this.name = name;
? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? public int getId() {
? ? ? ? ? ? ? ? ? return id;
? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ?public void setId(int id) {
? ? ? ? ? ? ? ? ?this.id = id;
? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ?}
? ?public class Student {
? ? ? ? private String name;
? ? ? ? private ArrayList courses;
? ? ? ? public Student(String name, ArrayList courses) {
? ? ? ? ? ? ? this.name = name;
? ? ? ? ? ? ?this.courses = courses;
? ? ? ? }
? ? ? ?public String getName() {
? ? ? ? ? ? return name;
? ? ? ? }
? ? ? ?public void setName(String name) {
? ? ? ? ? ?this.name = name;
? ? ? ? ?}
? ? ? public ArrayList getCourses() {
? ? ? ? ? return courses;
? ? ? ? }
? ? ?public void setCourses(ArrayList courses) {
? ? ? ? ?this.courses = courses;
? ? ? ?}
? ? }
? ? private void student() {
? ? ? ? ? Course yuwen = new Course("語文", 1);
? ? ? ? ? Course shuxue = new Course("數(shù)學", 2);
? ? ? ? ? Course yingyu = new Course("英文", 3);
? ? ? ? ? Course lishi = new Course("歷史", 4);
? ? ? ? ?Course zhengzhi = new Course("政治", 5);
? ? ? ? ?Course xila = new Course("希臘語", 6);
? ? ? ? ?ArrayList course1 = new ArrayList<>();
? ? ? ? ?course1.add(yuwen);
? ? ? ? ?course1.add(shuxue);
? ? ? ? ?course1.add(yingyu);
? ? ? ? ?course1.add(lishi);
? ? ? ? course1.add(zhengzhi);
? ? ? ? course1.add(xila);
? ? ? ? Student zhangsan = new Student("zhangsan", course1);
? ? ? ? Observable.just(zhangsan)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .flatMap(new Func1>() {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?@Override
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?public Observable call(Student student) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? return Observable.from(student.getCourses());
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }).subscribe(new Action1() {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?@Override
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?public void call(Course course) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? System.out.println(course.getName());
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?});
? ? ? ? ? ? ? ? ? ? ? }
8.和Retrofit一起使用
1.添加依賴:
compile 'com.squareup.retrofit2:retrofit:2.0.1'
compile 'com.squareup.retrofit2:converter-gson:2.0.1'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.1'
2.利用http://www.jsonschema2pojo.org創(chuàng)建數(shù)據(jù)模型
3.創(chuàng)建REST API 接口.注意此時返回的不能是Call而是Observable.示例代碼:
public interface LocationInterface {
? ? ? ? ? // http://ip.taobao.com/service/getIpInfo.php?ip=202.178.10.23
? ? ? ? ?@GET("/service/getIpInfo.php")
? ? ? ? ?public Observable getLocation(@Query("ip") String ip);
? }
4.創(chuàng)建Retrofit對象,發(fā)起請求.注意此時Retrofit需要添加addCallAdapterFactory.示例代碼:
? ? ? ? ? Retrofit retrofit = new Retrofit.Builder()
? ? ? ? ? ? ? ? ? ? ? .baseUrl(BASE2)
? ? ? ? ? ? ? ? ? ? ? .addConverterFactory(GsonConverterFactory.create())
? ? ? ? ? ? ? ? ? ? ? .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
? ? ? ? ? ? ? ? ? ? ? .build();
? ? ? ? LocationInterface locationInterface = retrofit.create(LocationInterface.class);
? ? ? ?Observable location = locationInterface.getLocation("8.8.8.8");
? ? ? ? ? ? ? ? ? ? ? location
? ? ? ? ? ? ? ? ? ? ?.subscribeOn(Schedulers.io())
? ? ? ? ? ? ? ? ? ? .map(new Func1() {
? ? ? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? ? ? public String call(Location location) {
? ? ? ? ? ? ? ? ? ? ? ? return location.getData().getCountry();
? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? })
? ? ? ? ? ? ? ? ? ?.observeOn(AndroidSchedulers.mainThread())
? ? ? ? ? ? ? ? ? .subscribe(new Action1() {
? ? ? ? ? ? ? ? ? @Override
? ? ? ? ? ? ? ? ? public void call(String s) {
? ? ? ? ? ? ? ? ? ? ? ?textView.setText(s);
? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ?});
? ? ? ? 以上就是這次整理的內容厚脉,整體來說就一個框架的內容,就是響應式編程的介紹胶惰,不夠我對這個東西算不上是熟悉的傻工,因為確實
沒有在正式的項目中使用過這個東西,但從平常的測試實踐中感覺這個確實對設計和解耦非常有幫助孵滞,不過自從看了kotlin之后精钮,覺得
這個東西就稍微差了一點點,這個東西仁者見仁智者見智吧剃斧,希望有研究過的小伙伴兒看一下轨香,有什么不對的地方及時的指正,一起分享
學習一下幼东。