今天來給大家介紹當下比較流行的響應式函數編程,以下是整理和蒐集整理的關於Rx的一些資料。響應式函數編程
確實是一種對新入行的人來說是一種新穎而又高效的編程方式。但是不建議新手採用這種方法進行立項,其中的牽扯到
觀察者模式,訂閱者模式還得等看過一定的算法和設計模式之後,才能理解的恰如其分,使用起來也可以得心應手,不過
在學習基礎的時候,理解和練習一些小的demo,對學習設計模式還是很有幫追的。今天介紹的實際上只有只有一種,就是
RxJava與RxAndroid,當然現在也有很多框架,像上幾篇提高的網絡請求OkGo都支持Rx的擴展,基於此給大家分享一下。
5、響應式函數編程Rx(Reactive Extensions)
主頁:https://github.com/ReactiveX/RxJava
中文資料:(這是一些大神分享一些學習的資料,參照的學習,確實英語有點尷尬了)
https://github.com/lzyzsd/Awesome-RxJava
https://www.zhihu.com/question/35511144
含義:
RxJava 的異步實現,是通過一種擴展的觀察者模式來實現的。
觀察者模式面向的需求是: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
作用: 決定什麼時候觸發事件以及觸發怎樣的事件
創建方法:
Observable.just(T...) 參數爲單個的
Observable.from(T[]) / Observable.from(Iterable) 參數爲數組或Iterable
2.觀察者: Observer
作用: 當事件觸發的時候將有怎樣的行爲
實現類有Observer / Subscriber
3.訂閱: subscribe
作用: 把Observable和Observer關聯起來
方法:
observable.subscribe(observer);
observable.subscribe(subscriber);
4.事件
onNext():普通事件
onCompleted():事件隊列完結
onError(): 事件隊列異常
需要注意的是onCompleted()和onError()是互斥的.調用了其中一個就不應該觸發另一個.
5.測試程序
現有一個數組 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 中,並在出現異常的時候打印 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 ,它們已經適合大多數的使用場景:
內置的Scheduler:
Schedulers.immediate(): 直接在當前線程運行,相當於不指定線程。這是默認的 Scheduler。
Schedulers.newThread(): 總是啓用新線程,並在新線程執行操作。
Schedulers.io(): I/O 操作(讀寫文件、讀寫數據庫、網絡信息交互等)所使用的 Scheduler。行爲模式和 newThread() 差不多,區別在於 io() 的內部實現是是用一個無數量上限的線程池,可以重用空閒的線程,因此多數情況下 io() 比 newThread() 更有效率。不要把計算工作放在 io() 中,可以避免創建不必要的線程。
Schedulers.computation(): 計算所使用的 Scheduler。這個計算指的是 CPU 密集型計算,即不會被 I/O 等操作限制性能的操作,例如圖形的計算。這個 Scheduler 使用的固定的線程池,大小爲 CPU 核數。不要把 I/O 操作放在 computation() 中,否則 I/O 操作的等待時間會浪費 CPU。
AndroidSchedulers.mainThread(): Android專用,它指定的操作將在 Android 主線程運行。
指定線程的方法:
Observable.subscribeOn():指定 subscribe() 所發生的線程,即 Observable.OnSubscribe 被激活時所處的線程。或者叫做事件產生的線程
Observable.observeOn():指定 Subscriber 所運行在的線程。或者叫做事件消費的線程。
7.數據變換
作用: 就是將事件序列中的對象或整個序列進行加工處理,轉換成不同的事件或事件序列
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("數學", 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創建數據模型
3.創建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.創建Retrofit對象,發起請求.注意此時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之後,覺得這個東西就稍微差了一點點,這個東西仁者見仁智者見智吧,希望有研究過的小夥伴兒看一下,有什麼不對的地方及時的指正,一起分享學習一下。
簡書地址:https://www.jianshu.com/p/9dec3c8b9bfd