原文地址: Dialogue between Rx Observable and a Developer (Me) [ Android RxJava2 ] ( What the hell is this ) Part5
原文作者:Hafiz Waleed Hussain
wow,新的一天又开始了,let's学点什么让这一天变得更加美妙吧。 hi,小伙伴们,希望你们一切都好,本文是RxJava2 Android系列的第五章 [part1, part2 , part3 ,part4 ]。本章我们将对RxJava Android下手,之前几章的学习已打下充分的基础,so let's do it now.
从这里开始的动机:老实说,学习RxJava的路上我踩了很多的坑,我阅读了大量的参考材料,然并卵,我还是没法将RxJava应用在自己的开发中。很多参考材料只是让我更加困惑,比如迭代器模式是基于pull操作,而Rx模式是基于push操作,虽然举了很多栗子,但对那时的我来说,效果甚微。我想学习RxJava,我想知道它的优点,我想借此摆脱成堆的bug和亢余的代码,但每次的阅读所得,都只是pull与push的比较,亦或是命令式与响应式编程的对比,这些都不是我想要的关于RxJava真谛。有些博主说,这就像观察者模式. 随着时间的流逝,困惑越来越多,学习的曲线也愈发困难。后来我阅读了一些函数响应式编程 (Functional Reactive Programming),lambda表达式,函数式编程相关的文章,其中包含大量的lambda的表达式,诸如Map,Filter之类的函数。但我仍然陷在无边泥沼里,因为我还是不知道RxJava是什么以及为什么要选择这种编程方式。之后我向一些使用RxJava的朋友取经,他们对我说,对于一款文本编辑器软件,如何知道用户修改了文本?我给出了我的答案,使用文本变化监听器(Listener)。 oh,可是实现这个监听器是很困难的,但是使用RxJava的debounce和简易的Rx observable可以让这个问题迎刃而解。当我问道使用RxJava只是为了省下十余行代码吗,他们的回答是No。你可以使用map,filter等其他函数让你的代码变得更加简洁。我不信这是RxJava的唯一好处,因为我完全可以创造一个类来实现以上需求。与此同时我也知道Netflix和其他的大公司也在使用Rx这种编程方式,他们的反馈也很棒.因此我更加困惑了。直到命运的那一天降临,我对自己说,开始干吧。虽然我还是不懂RxJava,但是我懂了我自己。学习的过程虽有间断,但从无放弃。通过阅读大量的参考材料,我已经学会了很多,但那就像支离破碎的拼图,现在是时候把它拼的完整了。 重要的一点是,我读过的所有材料和书籍都很重要,它们让我困惑,同时也让我学会了更多,在此衷心的感谢那些作者。 很重要的一点就是,我可以向你们做100%的保证,读完我的系列文章之后,你会了解RxJava的80%,不过别指望我会直接开始着手RxJava,我会从最基础的层次讲起,这个过程是缓慢的,但是到征途的最后,没人会困惑。 很长的动机,但也很重要,现在让我们开始吧。 我会使用IntelliJ 来编写测试用例。
学习RxJava的日子里,一天,我遇到了RxJava家族中的 Observable先生。所以我提出了很多了问题,所幸的是Observable先生很友善也很接地气。我曾认为RxJava很糟糕也很傲慢,不愿与开发者为友,而且装出一副高深莫测的样子唬人。当我和Observable先生开启了一段围炉夜谈后,我发现自己的想法是错的。谈话内容如下:
我:hello,Observable先生。最近日子咋样?
Observable:hi,Hafiz Waleed Hussain,我很好,thank u.
我:为什么学习你的曲线是如此的煎熬?为什么你那么的难学?看起来你并不想做开发之友。
Observable:haha,我确实想交很多的朋友,与此同时我也有一些很棒的朋友。这些朋友在其他的场合喜欢谈论我并且赞美我的能力。这些很棒的小伙子与我共度了很多时间。所以想保持良好的关系,你需要真挚的付出你的时间。问题就在这里,很多开发者想成为我的好朋友,但却不愿意花时间。他们一般都会开始着手了解我,几分钟后就开始玩手机,然后在接下来的几小时把我抛在了脑后。所以,你怎能指望我与一个并不诚恳付出的开发做朋友呢?
我:我懂了,那如果我想与你做朋友,那么我该怎么做?
Observable:专注我,多花些时间,然后你就会发现我有多么热情。
我:hmm,老实说,我并不是个擅长专注的人,反而,我很擅长选择性忽略,我该怎么利用忽略的能力呢?
Observable:那你应该忽略除我之外的所有,当你开始学习我的时候,那样的话,我会是你的益友。
我:wow,我觉得我们能成为好朋友。
Observable:任何人都可以让我成为他最好的朋友。
我:现在我有一些问题想提问。
Observable:你可以向我问上千个问题,当然,我需要你的诚恳。
我:当然可以保证。如果我有一些数据,现在我想把他们转为Observable形式,那我该如何以RxJava2 Android的方式实现。
Observable:这个问题的答案会很长。如果你看过我(Rx Java 2 Observable class)的源代码的话,你应该知道我有12904行代码。
每个方法都会返回一个Observable对象。我的社区里有很多的朋友,根据开发者的需要,我会利用我的朋友来构建自己,实现map,filter之类的功能。但这里我想和你分享一个方法,通过这个方法,世间万物皆可 Observable化。很抱歉,答案会很长,但绝不会无聊。我并不只会向你展示创建Observable对象的方法,我会教你如何用合适的方法重构当前的数据对象(data objects),将其转化为Observable的形式。
使用这个方法,你可以将任何对象(object)转为Observable,转化成的Observable可以发射(emit)该对象。
String data = "Hello World"; Observable.just(data).subscribe(s -> System.out.println(s)); Output: Hello World 复制代码
如果数据对象超过了一个,你可以使用如下API。
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; } 复制代码
我有很多丰富的API用来将你的数据结构转化为Observable,别问在哪,就在下面。
我认为API的命名已经表明了一切,所以无需对其做解释。当然我也会给你一些用例,这样你借鉴起来比较舒服。
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 + '/'' + '}';} } } 复制代码
From array:
public static void main(String[] args) { Integer[] values = {1,2,3,4,5}; Observable.fromArray(values) .subscribe(v-> System.out.print(v+" ")); } 复制代码
两个例子足以,你可以亲自动手尝试其他的。
你可以用这个API定义一个你想要的Observable.这个API会赐予你巨大的力量,但在我看来,使用这个API之前,你最好尝试下其他的解决方法。因为我相信其他的API已经可以解决你99%的问题。在别无选择的情况下,才去考虑使用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)); } 复制代码
这就像一个循环遍历,示例如下:
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))); } 复制代码
这个diao。我会向你展示一个栗子,你可以对比下两种实现方式。第一个例子我会使用java线程,而第二个例子我会使用interval().两者的输出相同。
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"); } 复制代码
另一个很棒的API.在编程中有时需要在一秒后执行某些操作,那么我就可以使用该API。
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"); } 复制代码
这个API在模拟对象(Mocking)时尤为有用。该API创造一个Observable,该Observable不会发射任何数据,但他可以具有一个Observable该有的流程。下面的用例展示在执行测试用例时会返回一个模拟数据(mock data),如果不是测试用例就会返回真实的对象。
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); } 复制代码
该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); } } 复制代码
以上代码的输出会是什么?如果你的答案中年龄是28,那你就错了。因为基本上所有创建Observable的方法在创建之时都会将传入的参数值保存在自身。如上用例所示,输出年龄会是27,因为创建时传入的值是27,之后虽然改为28,但Observable已然创建完了。so 如何解决这个问题?没错你可以使用API defer()。这真的很有用。当你使用defer时,基本上Observable 只会在你调用subscribe时才会被创建。所以使用该方法你就可以得到你最初预期的结果。(译者注,这看上去很像C语言中的指针,指向的是对象,而不是对象目前拥有的值)
Observable getObservable(){ //return Observable.just(name, age); return Observable.defer(()-> Observable.just(name, age)); } 复制代码
现在年龄输出是28了。
这个也很有用,它可以用来产生一个错误信号(error signal)。以后我们讨论Observer和它的方法时,我会向你详细介绍这个API。
该API不发送任何事件。 (译者注:看到这里还记得这是一段对话吗?) 我:wow,Observable很感谢你给出了这段长且健壮的回答,我会把这个答案当作一个备忘单。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; } 复制代码
我:wow,你真的是太强了。目前我想向你请教一些map,filter之类操作,但你与我分享了Observable创建的知识。对此我无法向你发问,因为我在这一块的知识很匮乏,所以请与我分享更多吧。
Observable:这将是一个漫长的过程,我们有很多要谈的。但我想在这里我可以向你解释两种类型的Observable。一个被称为Cold Observable,另一个被称作Hot Observable.对于Cold Observable,....(未完待续)