又是新的一天,是時候學點新東來西來讓今天變得酷炫了。前端
你們好,但願大家都過的不錯。這是咱們 RxJava2 Android 系列的第五篇文章 [ part1, part2, part3, part4 ] 。在這篇文章中,咱們會繼續研究 Rx Java Android 。java
動機:react
動機和我在第一部分 part1 中分享給你們的同樣。如今咱們把以前 4 篇學到的東西融會貫通起來。android
介紹:ios
當我在學習 Rx java Android 的某一天,我有幸與一位 Rx Java 的 Observable 類進行了親切友好的交談。好消息是 Observable 類很厚道,令我驚歎不已。我一直覺得 Rx Java 是個大坑逼。他/她不想和開發者作朋友,總給他們穿小鞋。
可是在和 Observable 類談話之後,我驚喜的發現個人觀點是錯的。git
我:你好,Observable 類,吃了嘛您?github
Observable 類:你好 Hafiz Waleed Hussain ,我吃過啦。express
我:爲啥你的學習曲線這麼陡峭?爲啥你故意刁難開發者?你這麼搞要沒朋友了。後端
Observable 類:哈哈,你說的是。我真想交不少朋友,不過我如今也有一些好哥們兒。他們在不一樣的論壇上討論我,介紹我和個人能力。並且這些傢伙真的很棒,他們花了好久的時間和我呆在一塊兒。只有精誠所至,纔會金石爲開。但問題是,不少想撩個人人只走腎不走心。他們關注我了一小會就去刷推特臉書,把我給忘了。因此說,對我不真誠的人又如何期望我和他們交朋友呢?數組
我:好吧,若是想和你交朋友的話,我該怎麼作?
Observable 類:把注意力集中在我身上,而且堅持足夠長的時間,而後你就知道我有多真誠了。
我:嗯,實話實說我不擅長集中精神,可是我擅長無視周圍。這樣能夠嘛?
Observable 類:固然,只要你和我在一塊兒的時候能夠心無旁騖,我會是你的好朋友的。
我:哇哦,我有種預感,我會和你交上朋友的。
Observable 類:固然,任何人均可以把我當好朋友。
我:如今我有些問題,能夠問了嘛?
Observable 類:固然,你能夠問成千上萬個問題。我會給你答案,可是重要的是須要你本身花時間去思考和吸取。
我:我會的。若是我想把數據轉化爲 Observable 對象,在 Rx Java 2 Android 裏怎麼實現?
Observable 類:這個問題的答案很長很長。若是你來看我(Rx Java 2 Observable 類)的源碼,你就會發現我一共有12904行代碼。(校對 Phoenix 注:在 RxJava 2.0.9 版本。Observable 類已經成功增肥到 13728 行。)
個人團隊裏也有好幾個朋友,能夠根據開發者的需求返回 Observable 對象,好比 map ,filter。不過如今我會告訴你幾個能夠幫助你把任何東西轉化爲 Observable 對象的方法。抱歉個人回答可能會很長,可是也不會很無聊。我不只僅會演示這些方法如何建立 Observable 對象,同時也會向你展現如何對手頭邊代碼進行重構。
1 just()
經過這個方法,你能夠把任意(多個)對象轉化成以此對象爲泛型的 Observable 對象( Observable
String data= "Hello World";
Observable.just(data).subscribe(s -> System.out.println(s));
Output:
Hello World複製代碼
若是你的數據不止一個,能夠像下面那樣調用 just 方法 :
String data= "Hello World";
Integer i= 4500;
Boolean b= true;
Observable.just(data,i,b).subscribe(s -> System.out.println(s));
Output:
Hello World
4500
true複製代碼
此 API 最多可接收 10 個數據作參數。
Observable.just(1,2,3,4,5,6,7,8,9,10).subscribe(s -> System.out.print(s+" "));
Output:
1 2 3 4 5 6 7 8 9 10複製代碼
樣例代碼:(不是個好例子,只是給點提示,告訴你如何在本身的代碼中使用)
public static void main(String[] args) {
String username= "username";
String password= "password";
System.out.println(validate(username, password));
}
private static boolean validate(String username, String password) {
boolean isUsernameValid= username!=null && !username.isEmpty() && username.length() > 3;
boolean isPassword= password!=null && !password.isEmpty() && password.length() > 3;
return isUsernameValid && isPassword;
}複製代碼
使用 Observable 類進行重構:
private static boolean isValid= true;
private static boolean validate(String username, String password) {
Observable.just(username, password).subscribe(s -> {
if (!(s != null && !s.isEmpty() && s.length() > 3))
throw new RuntimeException();
}, throwable -> isValid= false);
return isValid;
}複製代碼
2 from…
:
我有一大堆的 API 能夠把複雜的數據結構轉化爲 Observable 對象,好比下面那些以關鍵字 from 開頭的方法:
我想這些 API 從名字就能夠看懂它們的意思,因此也不須要更多解釋了。不過我會給你一些例子,這樣你能夠在本身的代碼裏用的更舒服。
(校對 Phoenix 注:
雖然 fromCallable, fromPublisher, fromFuture 也是 from 開頭的方法。可是他們互相之間區別很大。尤爲是 fromCallable 和 fromPublisher。)
public static void main(String[] args) {
List<Tasks> tasks= Arrays.asList(new Tasks(1,"description"),
new Tasks(2,"description"),new Tasks(4,"description"),
new Tasks(3,"description"),new Tasks(5,"description"));
Observable.fromIterable(tasks)
.forEach(task -> System.out.println(task.toString()));
}
private static class Tasks {
int id;String description;
public Tasks(int id, String description) {this.id= id;this.description = description;}
@Override
public String toString() {return "Tasks{" + "id=" + id + ", description='" + description + '\'' + '}';}
}
}複製代碼
從數組轉化爲 Observable 對象
public static void main(String[] args) {
Integer[] values= {1,2,3,4,5};
Observable.fromArray(values)
.subscribe(v-> System.out.print(v+" "));
}複製代碼
兩個例子就夠啦,回頭你能夠親自試試其餘的。
3 create()
:
你能夠把任何東西強行轉爲 Observable 對象。這個 API 過於強大,因此我的建議使用這個API以前,應該先找找有沒有其餘的解決方式。大約99%的狀況下,你能夠用其餘的 API 來解決問題。但若是實在找不到,那麼就用它也能夠。
(校對 Phoenix 注:這裏可能做者對 RxJava 2 的 create 還停留在 RxJava 1 的階段。 RxJava 1.x 確實不推薦 create 方法。而 RxJava 2 的 create 方法是推薦方法。並非 99% 的狀況均可以被取代。 RxJava 1.x 的 create 方法現已經成爲 RxJava 2.x 的 unsafeCreate ,RxJava 1.2.9 版本也加入了新的安全的 create 重載方法。)
public static void main(String[] args) {
final int a= 3, b = 5, c = 9;
Observable me= Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> observableEmitter) throws Exception {
observableEmitter.onNext(a);
observableEmitter.onNext(b);
observableEmitter.onNext(c);
observableEmitter.onComplete();
}
});
me.subscribe(i-> System.out.println(i));
}複製代碼
4 range()
:
這就像是一個 for 循環,就像下面的代碼顯示的那樣。
public static void main(String[] args) {
Observable.range(1,10)
.subscribe(i-> System.out.print(i+" "));
}
Output:
1 2 3 4 5 6 7 8 9 10複製代碼
再來一個例子:
public static void main(String[] args) {
List<String> names= Arrays.asList("Hafiz", "Waleed", "Hussain", "Steve");
for (int i= 0; i < names.size(); i++) {
if(i%2== 0)continue;
System.out.println(names.get(i));
}
Observable.range(0, names.size())
.filter(index->index%2==1)
.subscribe(index -> System.out.println(names.get(index)));
}複製代碼
5 interval()
:
這個 API 碉堡了。我用兩種方法實現同一種需求,你能夠比較一下。第一種我用 Java 的線程來實現,另外一種我用 interval() 這個 API ,兩種方法會獲得同一個結果。
(校對 Phoenix 注:interval() 會默認在 Scheduler.computation() 進行操做。)
public static void main(String[] args) {
new Thread(() -> {
try {
sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
greeting();
}).start();
Observable.interval(0,1000, TimeUnit.MILLISECONDS)
.subscribe(aLong -> greeting());
}
public static void greeting(){
System.out.println("Hello");
}複製代碼
6 timer()
:
又是一個好的 API。在程序中若是我想一秒鐘後調用什麼方法,能夠用 timer ,就像下面展現的那樣:
public static void main(String[] args) throws InterruptedException {
Observable.timer(1, TimeUnit.SECONDS)
.subscribe(aLong -> greeting());
Thread.sleep(2000);
}
public static void greeting(){
System.out.println("Hello");
}複製代碼
7 empty()
:
這個 API 頗有用,尤爲是在有假數據的時候。這個 API 建立的 Observable 對象中,註冊的 Observer 對象只調用 complete 方法。好比這個例子,若是在測試運行時發送給我假數據,在生產環境下就調用真的數據。
public static void main(String[] args) throws InterruptedException {
hey(false).subscribe(o -> System.out.println(o));
}
private static Observable hey(boolean isMock) {
return isMock ? Observable.empty(): Observable.just(1, 2, 3, 4);
}複製代碼
8 defer()
:
這個 API 在不少狀況下都會頗有用。我來用下面的例子解釋一下:
public static void main(String[] args) throws InterruptedException {
Employee employee= new Employee();
employee.name= "Hafiz";
employee.age= 27;
Observable observable= employee.getObservable();
employee.age= 28;
observable.subscribe(s-> System.out.println(s));
}
private static class Employee{
String name;
int age;
Observable getObservable(){
return Observable.just(name, age);
}
}複製代碼
上面的代碼會輸出什麼呢?若是你的答案是 age = 28 那就大錯特錯了。基本上全部建立 Observable 對象的方法在建立時就記錄了可用的值。就像剛纔的數據實際上輸出的是 age = 27 , 由於在我建立 Observable 的時候 age 值是 27 ,當我把 age 的值變成 28 的時候 Observable 類已經建立過了。因此怎麼解決這個問題呢?是的,這個時候就輪到 defer 這個 API 出場了。太有用了!當你使用 defer 之後,只有註冊(subscribe)的時候才建立 Observable 類。用這個 API ,我就能夠得到想要的值。
Observable getObservable(){
//return Observable.just(name, age);
return Observable.defer(()-> Observable.just(name, age));
}複製代碼
這樣咱們的 age 的輸出值就是 28 了。
(校對 Phoenix 注:Observable 的建立方法中,並非像原文中寫到的,「基本上全部建立 Observable 的方法在建立時就記錄了可用的值」。而是隻有 just, from 方法。 create , fromCallable 等等方法都是在 subscribe 後纔會調用。文中的例子可使用 fromCallable 代替 defer。)
9 error()
:
一個能夠彈出錯誤提示的方法。當咱們討論 Observer 類和他的方法的時候,我再和你分享吧。
10 never()
:
這個 API 建立出的 Observable 對象沒有包含泛型。
(譯者注:Observable.never 雖然能夠獲得一個 Observable 對象,可是註冊的對應 Observer 既不會調用 onNext 方法也不會 onCompleted 方法,甚至不會調用 onError 方法)
我:哇哦。謝謝你,Observable 類。謝謝你耐心又詳細的回答,我會把你的回答記在個人祕籍手冊上的。話說,你能夠把函數也轉化成 Observable 對象嗎?
Observable 類:固然,注意下面的代碼。
public static void main(String[] args) throws InterruptedException {
System.out.println(scale(10,4));
Observable.just(scale(10,4))
.subscribe(value-> System.out.println(value));
}
private static float scale(int width, int height){
return width/height*.3f;
}複製代碼
我:哇哦,你真的好強大。如今我想問你有關操做符,好比 map ,filter 方面的問題。可是有關 Observable 對象建立,若是還有什麼我由於缺少知識沒問到的地方,再多告訴我一點唄。
Observable 類:其實還有不少。我在這裏介紹兩類 Observable 對象。一種叫作 Cold Observable,第二個是 Hot Observable。在...
總結:
你們好。這篇對話已經很是很是的長,我須要就此擱筆了。否則這篇文章就會像大部頭的書,可能看上去不錯,可是主要目的就跑偏了。我但願,咱們能夠按部就班的學習。因此我要暫停個人對話,而後在下一篇繼續。讀者能夠試試親自實現這些方法,若是可能的話在實際的項目中去運用、重構。最後我想說,謝謝 Observable 類給我了這麼多他/她的時間。
週末愉快,再見~
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、React、前端、後端、產品、設計 等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃。