Maxwell's Growth Path

主要记录学习中遇到的问题和技术分享

最新文章

2017-08-11
RxJava 2.x 使用详解(六) 变换操作符

前序

  忙了一段时间后赶紧趁着空闲时间填一下坑,文章其实写了一段时间但是没有发布,最近校对下确保没有错误发出来。本期将介绍下RxJava的变换操作符,也是最后一期常用操作符的介绍。

Map

  基本的转换操作符,可以把每一个元素转换成新的元素发射,接收一个Function<T,R>作为转换逻辑的操作,下面是例子:

Flowable.just(1, 2, 3)
        .map(integer -> "int" + integer)
        .subscribe(ele -> Log.i("tag", String.valueOf(ele)));

  上述例子中map操作符返回了Flowable<String>,最终输出的结果为:int1、int2、int3。

flatMap

  上面的Map操作符是把每一个元素转换成一个新的元素,但是flatMap操作符是把每一个元素转换成新的被观察者,每个被观察者发射的元素将会合并成新的被观察者,这些元素顺序输出,例如下面的:

Flowable.just(1, 2, 3 …
[ 阅读全文 ]
2017-06-30
RxJava 2.x 使用详解(五) 条件操作符

前序

  本期将会介绍条件操作符,用于控制被观察者开始、停止、跳过的各种条件操作符。本文均使用lambda表达式来书写代码,如果不熟悉的朋友可以在IDE中瞧一瞧原来的接受的参数即可。(本文主要是简化了Predicate类型参数)

all

  要判断所有元素是否满足某个条件,可以使用all操作符,它接受一个Predicate,其中的test方法用于判断某个元素是否满足条件,最终输出是否所有元素都满足条件,比如下面例子:

Flowable.just(1, 2, 3)
        .all(integer -> integer >= 0)
        .subscribe(ele -> Log.i("tag", String.valueOf(ele)));

  上述例子是判断是否所有元素都大于等于0,all操作符会把被观察者转换成Single<Boolean>类型的被观察者,最终输出结果为true。

ambArray

  ambArray操作符可以从多个被观察者中选择第一个发射元素的被观察者进行处理,其他被观察者则抛弃,比如:

Flowable.ambArray(
        Flowable.timer(1, TimeUnit.SECONDS),
        Flowable.just …
[ 阅读全文 ]
2017-06-29
RxJava 2.x 使用详解(四) 合并聚合操作符

前序

  这期我们来说一下RxJava中合并操作符和聚合操作符,主要用于合并多个被观察者或者把一个观察者的多个元素聚合成一个元素。文章先从合并操作符开始说明,当切换到聚合操作符时,文章会提到。

startWith / startWithArray

  如果你需要在被观察发送元素之前追加数据或者追加新的被观察者,这时候可以使用startWith操作符,例子如下:

Flowable.just(4, 5, 6)
        .startWith(Flowable.just(1, 2, 3))
        .startWith(0)
        .subscribe(ele -> Log.i("tag", String.valueOf(ele)));

  上述代码输出结果为“0,1,2,3,4,5,6”,如果你需要追加多个元素,则需要使用另外一个操作符startWithArray,一次追加多个元素。

Flowable.just(4, 5, 6)
        .startWithArray(1 …
[ 阅读全文 ]
2017-06-28
RxJava 2.x 使用详解(三) 过滤操作符

前序

  上篇说到RxJava创建操作符,这一节来说说过滤操作符,还记得上节中说到interval操作符如果没有其他限制的话就会无限发送onNext事件,永远也不会调用onComplete事件,如果需要限制的话,可以使用一些过滤操作符进行限制。

filter

  先说一个基本的过滤操作符filter,可以自己设定任意的规则来过滤数据,比如过滤出大于等于2的元素:

Flowable.just(1, 2, 3)
        .filter(new Predicate<Integer>() {
            @Override
            public boolean test(Integer integer) throws Exception {
                //过滤出>=2的数据
                return integer >= 2;
            }
        })
        .subscribe(integer -> Log.i("tag", String.valueOf(integer)));

  上面的结果只会输出2和3,因为boolean test(T t)方法返回true则表示元素数据有效,否则则为无效抛弃。

take …

[ 阅读全文 ]
2017-06-08
RxJava 2.x 使用详解(二) 创建操作符

前序

  上篇说到RxJava给我们提供各种操作符来处理日常处理操作,今天我们来详细分析下各种操作符的作用和用法。为此我之前花了点时间增加了博文的目录导航功能,方便大家查阅时候使用。

  由于本文主要讲述操作符作用,本文使用lambda表达式来简化代码,如果不熟悉lambda的读者可以参考我之前的文章,如果涉及前文没有提到的类会不使用lambdb来表示。

just

  首先回想一下第一篇中说到的被观察者可以采用Flowable、Observable、Single等等的create方法来实现,如果对于只是发送几个数据来说,这个过程未免十分复杂繁琐,可以使用just操作符来简化:

Flowable.just("test","test2")
        .subscribe(str -> Log.i("tag", str));

  上述代码相当于顺序调用onNext("test")onNext("test2"),然后调用onComplete方法。

  另外还可以使用Observable、Single或者Maybe来调用这个操作符。对于Completable则不能使用(因为没有onNext事件),对于Flowable和Observable最多能接收10个参数,也就是发送10个数据,而Single和Maybe只能接收1个参数(只能发送一次onNext事件)。这些都是理解了本质就能明白为什么会这样,所以下面的操作符非特殊情况就不再一一说明各种被观察者使用区别。

fromArray

  之前说到的just操作符,最多只能接收10个参数。我们通过观察just操作符的源码发现 …

[ 阅读全文 ]
2017-06-06
RxJava 2.x 使用详解(一) 快速入门

前序

  最近打算写一篇完整的RxJava/RxAndroid 2.x使用详解,一方面网上没有找到比较完整的教程,完整的教程又不是面向基础读者,或者还停留在RxJava 1.x的版本中,一方面自己可以当做一个学习笔记,什么时候忘记了也可以快速查一下。

  本文就不再讨论Rxjava 1.x和2.x两个版本有什么区别,关于这个可以参考官方wiki,可能现在还看不懂,没关系,可以直接学习2.x,我认为新的迟早要普及,旧版项目也会迁移到新的上。

  另外本文尽量不使用Lambda表达式,方便读者理解。

概念

  首先知道什么是RxJava,Rx是ReactiveX的缩写,而ReactiveX是Reactive Extensions的缩写。RxJava顾名思义即使Java上的异步和基于事件响应式编程库。

  RxJava基于观察者模式,主要有四个部分:观察者、被观察者、订阅、事件。这样说很难说的明白,我们马上举一个例子来说明。

Hello RxJava

  首先根据上面说的,首先需要一个观察者,可以通过创建FlowableSubscriber,由于事件处理的数据类型不一样,FlowableSubscriber需要一个泛型来说明这个数据类型,这里假设我们要处理String类型数据 …

[ 阅读全文 ]
2017-06-02
Android中的Lambda表达式详解

前序

  Lambda表达式是一个看上去很难懂的语法糖,目前有一种趋势表明它越来越火,各种语言都开始支持Lambda表达式。即使你不使用这种语法糖,你也应该去学习了解,否则你可能看不懂很多代码。

  不过由于Java8才引入Lambda表达式,而Android Studio一直都是嵌入JDK(Java Development Kit)1.7,自然要在Android Studio上使用Lamda表达式,这时候只能靠开源力量,自然就有Retrolambda这个Gradle插件。

  当然Lambda的好处、缺点这里就不解析了,当然我认为无论你是否使用,Lambda也是需要学习的一个语法糖。本文为了方便阅读,尽可能避免会涉及到其他Java8的新特性。

引入Retrolambda

  首先需要使用Lambda,你要有一个JDK(Java Development Kit)1.8,修改你的项目JDK版本为1.8及以上的版本,如下图所示: jdk   接下来需要在Application的build.gradle中添加Retrolambda插件(来自mavenCentral依赖库):

buildscript {

    repositories {
        mavenCentral()
        //...
    }
    dependencies {
        classpath 'me.tatarka:gradle-retrolambda:3 …
[ 阅读全文 ]
2017-06-01
Android单元测试之AssertJ框架

前序

  上一篇Android单元测试文章说到如果使用Junit给我们提供的Assert去对比Intent,那就需要每个成员都对比一次,十分不方便,今天给大家带来一个十分便利的框架AssertJ,由于这个框架本身是给Java使用的,我们可以直接使用针对Android设计的AssertJ-Android框架。这个框架官方说明中写道“... aims to make it even easier to test Android”(致力于让安卓测试更简单),它和Assertj原版的比较可以看看官方的说明,这个不是本文的重点,这里就不多说了。

Gradle依赖

  首先当然是引入AssertJ-Android,直接在app的build.gradle中添加:

testCompile 'com.squareup.assertj:assertj-android:1.1.1'

  如果遇到冲突问题,比如:

Conflict with dependency 'com.android.support:support-annotations' in project ':app'. Resolved versions for …

[ 阅读全文 ]
2017-05-26
Android单元测试之Robolectric框架

前序

  上一篇Android单元测试文章最后说道要测试Android代码逻辑,光有JUnit和Mockito是不够的,假设你使用了TextView的setText,用Mockito框架的话,默认的TextView的getText方法会返回null,如果是简单的代码,使用Mockito的桩设置还可以接受,如果是要测试到Activity的生命周期等一些复杂逻辑就显得比较复杂了。

  为了解决这个问题,诞生了Instrumentation、Robolectric等等的测试框架,不过Instrumentation实际上还是要运行代码到平台上测试,耗费大量的时间,我们今天要介绍的是运行在JVM上的Robolectric测试框架。

  PS:本来想找一些参考文章,结果发现网上的文章多半是说一半没有另一半,或者有些可能遇到的问题没有指出。最主要的是官方的文档也是少的可怜,给出的Sample也是旧版本的,完全很多地方都不一样了。

Robolectric基本原理

  在使用Robolectric之前我们先要明白Robolectric是如何工作的。比如说我们前文说到的TextView,如果我们使用Mockito,他给我们提供的是Mock后的TextView,而Robolectric给我们提供的是ShadowTextView,这个ShadowTextView实现了TextView身上的方法,但他又与Android的运行环境无关,也就是说他可以像使用TextView一样的方法,但不用在平台上运行代码,大大提高测试效率。

特别注意事项

  使用Robolectric要注意它的版本以及其支持的SDK版本,如果不支持千万不要用高版本SDK编译,或者升级Gradle插件和编译器版本,否则运行时会出现各种问题。如果版本太高,例如我尝试使用Gradle Wrapper版本4.0配合Gradle插件3.0.0版本时发现是无法成功测试的。

  本文采用最新的Robolectric 3.x(目前是3.4-rc2 …

[ 阅读全文 ]
2017-05-25
Android单元测试之Mockito框架

前序

  之前写的JUnit框架单元测试的最后留了一个悬念,今天我们把这个问题解决下,首先我们要理解mock的概念,然后学习使用mock来做单元测试。关于Mock的框架有很多,比如Mockito、PowerMock、EasyMock等等,本文主要介绍Mockito的用法,各种框架的对比不在本文阐述范围,而且此类框架大体相同,只需要学习其中一个就能轻松地学习其他框架,没必要纠结那个框架才是最好的。

Mock的概念

  首先要明白什么是Mock,为什么要Mock,Mock能干什么这三个问题。Mock的中文意思是“模仿”,Mock就是去构造(模仿)一个虚拟的对象,而这个对象通常比较难直接创建,有了Mock可以轻松地帮助你对复杂的功能解耦,实现单元测试。比如前文最后留下的Log类,你会发现它依赖于Android运行环境,很难把整个依赖树都构建出来,所以我们需要Mock。

集成Mocktio

  Android上集成非常简单,在app项目下的build.gradle添加测试编译依赖(下面采用2.x最新版本):

dependencies {
    //...
    testCompile "org.mockito:mockito-core:2.+"
}

  然后使用Gradle Sync一下即可。顺便附上Mockito的Jcenter地址:http …

[ 阅读全文 ]