@pockry
2016-04-05T16:50:40.000000Z
字数 3837
阅读 1434
移动
node-id:rxandroid-basics-2
原文链接:https://medium.com/@kurtisnusbaum/rxandroid-basics-part-2-6e877af352#.sep65ql44
欢迎回来!看来你想更多的了解RxJava。如果你还没有看第一部分(此处链接有待修改),推荐先看第一篇。现在我们来看其他几个例子。再说一遍,所有的例子都可以在这个repo里找到。在每个例子的开始,我都会说明代码是属于哪个Activity的。
现在我们写一个Activity,里面要展示一个数字并有一个自增按钮。在看代码之前,先介绍另一个有关RxJava的概念,Subject。Subject这个对象既是Observable又是Observer,我会把Subject想象成一个管道:从一端把数据注入,结果就会从另一端输出。
Subject有好几类,在这里我们使用最简单的:PublishSubject。使用PublishSubject时,一旦数据从一端注入,结果会立即从另一端输出。
首先我们要写这个管道的输出端。刚才说了Subject也是Observable,也就是说我们可以像观察任何一个Observable一样观察它。这段代码的功能就是观察管道的输出端到底输出了什么。我们在这里写一个很简单的Observer来更新mCounterDisplay控件。
mCounterEmitter = PublishSubject.create();
mCounterEmitter.subscribe(new Observer<Integer>() {
@Override
public void onCompleted() { }
@Override
public void onError(Throwable e) { }
@Override
public void onNext(Integer integer) {
mCounterDisplay.setText(String.valueOf(integer));
}
});
与第一部分中的例子不同,在这个例子中onNext()会被调用多次。每次发送新的数据时,mCounterDisplay都会展示新的数据。但是PublishSubject怎么发送数据呢?让我们看一下mIncrementButton的监听代码。
mIncrementButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCounter++;
mCounterEmitter.onNext(mCounter);
}
});
可以看到mIncrementButton在onClick()回调方法中做了两件事情:
让mCounter变量自增。
调用mCounterEmitter的onNext()方法并传入mCounter。
由于Subject同时也是Observer,所以它也有onNext()方法,因此我们可以通过调用onNext()方法把数据注入管道的输入端,可以理解为同我们在一端中观察自增按钮是否被点击,然后把信息告知管道另一端的Observer。
我们现在要写一个只显示一个数字的Activity。这将是一个很简单的Activity,因为我们要在这里使用map方法。如果你接触过函数式编程,你可能对map并不陌生。你可以把map当做一个方法,它接收一个数据,然后输出另一个数据,当然输入输出的两个数据之间是有联系的。
我们先写一个只发送一个数字4的Single对象。
Single.just(4).map(new Func1<Integer, String>() {
@Override
public String call(Integer integer) {
return String.valueOf(integer);
}
}).subscribe(new SingleSubscriber<String>() {
@Override
public void onSuccess(String value) {
mValueDisplay.setText(value);
}
@Override
public void onError(Throwable error) { }
});
我们最终要显示Single所发送的数据,但首先我们需要将这个数据从Integer转为String,而这里的解决方法就是使用map()函数。正如刚才所说,map接收一个数据,进行处理而后输出它,这正是我们需要的。现在Single会发送数字4,我们使用map()方法将其转为String,而后交给Observer去展示它。
这个例子中对于map方法的使用很轻量,不过map可是非常强大的,在下一个例子中你可以看到,map可以被用来执行任意代码,在处理数据方面起到很重要的作用。
现在我们要写一个用来根据名字搜索城市的Activity。在这个Activity中,我们要使用在这两篇文章中所学的所有知识并写一个比较大的例子。同时还要介绍一个新的概念:deboundce。开始。
现在我们要写一个PublishSubject,并能接收用书输入进输入框的数据,而后根据输入获取符合的列表,并展示。
mTextWatchSubscription = mSearchResultsSubject
.debounce(400, TimeUnit.MILLISECONDS)
.observeOn(Schedulers.io())
.map(new Func1<String, List<String>>() {
@Override
public List<String> call(String s) {
return mRestClient.searchForCity(s);
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<String>>() {
@Override
public void onCompleted() { }
@Override
public void onError(Throwable e) { }
@Override
public void onNext(List<String> cities) {
handleSearchResults(cities);
}
});
mSearchInput.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { }
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
mSearchResultsSubject.onNext(s.toString());
}
@Override
public void afterTextChanged(Editable s) { }
});
这段代码有不少内容,让我们一点一点分析。
首先你会看到debounce()方法。这是啥?有啥用?如果你看一下我们是如何给输入框添加监听器的,你会发现每当输入的内容改变时都会有输入发送到mSearchResultsSubject,不过我们不想让用户每点一个键都向服务器请求一次。我们想等一会,等用户停止输入(代表差不多输完)的时候再请求服务器。
而debounce()方法就是做这个的。这个方法告诉mSearchResultsSubject在没有数据传入达400毫秒时才发送数据。意思就是,仅当用户400ms都没有改变输入内容时,Subject才会发送最新的搜索字符串。这样以来我们就不会进行无意义的网络请求了,UI也不会每输入一个字符都更新。
我们想通过RestClient来访问服务器,而因为RestClient涉及IO操作,我们需要在IO Scheduler中进行这个操作,所以要写observeOn(Schedulers.io())。
好了,现在我们会把搜索字段发送到IO Scheduler中,在这里map就要发挥作用了,我们在map方法中通过关键字获取搜索结果的列表。在map中我们可以调用任意外部方法,在这里使用RestClient获取搜索结果。
因为map方法会在IO Scheduler中运行,而我们又要用其返回值填充View,所以要重新切换到UI线程,所以要写observeOn(AndroidSchedulers.mainThread())。现在搜索结果会被发送到UI线程。要注意两个observeOn()方法的顺序,这一点至关重要。现在我们总结一下数据发送的顺序。
mSearchResultsSubject
|
|
V
debounce
|||
|||
V
map
|
|
V
observer
一个竖杠代表数据在UI线程中发送,三个竖杠代表数据在IO Scheduler中发送。
最终,我们获得搜索结果,并展示给用户。
有关RxJava就说这么多了,希望这两篇文章能帮你了解RxJava的基础。强烈建议你自己探索有关RxJava的其他方面。如果你有问题或者只是想说点什么,欢迎在下方留言。