转载

[译] Rx Observable与一个开发者的围炉夜谈(RxJava到底是什么) 第五部分x

原文地址: 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行代码。

[译] Rx Observable与一个开发者的围炉夜谈(RxJava到底是什么) 第五部分x

每个方法都会返回一个Observable对象。我的社区里有很多的朋友,根据开发者的需要,我会利用我的朋友来构建自己,实现map,filter之类的功能。但这里我想和你分享一个方法,通过这个方法,世间万物皆可 Observable化。很抱歉,答案会很长,但绝不会无聊。我并不只会向你展示创建Observable对象的方法,我会教你如何用合适的方法重构当前的数据对象(data objects),将其转化为Observable的形式。

  1. just():

使用这个方法,你可以将任何对象(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
复制代码
[译] Rx Observable与一个开发者的围炉夜谈(RxJava到底是什么) 第五部分x

示例代码:(可能并不好,但会指导你如何将其应用在自己的编码中)

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;
}

复制代码
  1. from… :

我有很多丰富的API用来将你的数据结构转化为Observable,别问在哪,就在下面。

[译] Rx Observable与一个开发者的围炉夜谈(RxJava到底是什么) 第五部分x

我认为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+" "));
}
复制代码

两个例子足以,你可以亲自动手尝试其他的。

  1. create():

你可以用这个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));
}
复制代码
  1. range():

这就像一个循环遍历,示例如下:

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)));
}
复制代码
  1. interval():

这个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");
}
复制代码
  1. timer():

另一个很棒的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");
}
复制代码
  1. empty():

这个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);
}
复制代码
  1. 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);
    }
}
复制代码

以上代码的输出会是什么?如果你的答案中年龄是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了。

  1. error():

这个也很有用,它可以用来产生一个错误信号(error signal)。以后我们讨论Observer和它的方法时,我会向你详细介绍这个API。

  1. never():

该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,....(未完待续)

原文  https://juejin.im/post/5d654043e51d4561a54b69d7
正文到此结束
Loading...