处理耗时的任务
我们已经知道如何处理缓慢的I/O操作。让我们看一个与I/O无关的耗时的任务。例如,我们修改loadList()函数并创建一个新的slow函数发射我们已安装的app数据。
1
private Observable<AppInfo> getObservableApps(List<AppInfo> apps) {
2
return Observable .create(subscriber -> {
3
for (double i = 0; i < 1000000000; i++) {
4
double y = i * i;
5
}
6
for (AppInfo app : apps) {
7
subscriber.onNext(app);
8
}
9
subscriber.onCompleted();
10
});
11
}
Copied!
正如你看到的,这个函数执行了一些毫无意义的计算,只是针对这个例子消耗时间,然后从List<AppInfo>对象中发射我们的AppInfo数据,现在,我们重排loadList()函数如下:
1
private void loadList(List<AppInfo> apps) {
2
mRecyclerView.setVisibility(View.VISIBLE);
3
getObservableApps(apps)
4
.subscribe(new Observer<AppInfo>() {
5
@Override
6
public void onCompleted() {
7
mSwipeRefreshLayout.setRefreshing(false);
8
Toast.makeText(getActivity(), "Here is the list!", Toast.LENGTH_LONG).show();
9
}
10
11
@Override
12
public void onError(Throwable e) {
13
Toast.makeText(getActivity(), "Something went wrong!", Toast.LENGTH_SHORT).show();
14
mSwipeRefreshLayout.setRefreshing(false);
15
}
16
17
@Override
18
public void onNext(AppInfo appInfo) {
19
mAddedApps.add(appInfo);
20
mAdapter.addApplication(mAddedApps.size() - 1, appInfo);
21
}
22
});
23
}
Copied!
如果我们运行这段代码,当我们点击Navigation Drawer菜单项时App将会卡住一会,然后你能看到下图中半关闭的菜单:
如果我们不够走运的话,我们可以看到下图中经典的ANR信息框:
可以确定的是,我们将会看到下面在logcat中不愉快的信息:
1
I/Choreographer Skipped 598 frames! The application may be doing too much work on its main thread.
Copied!
这条信息比较清楚,Android在告诉我们用户体验非常差的原因是我们用不必要的工作量阻塞了UI线程。但是我们已经知道了如何处理它:我们有调度器!我们只须添加几行代码到我们的Observable链中就能去掉加载慢和Choreographer信息:
1
getObservableApps(apps)
2
.onBackpressureBuffer()
3
.subscribeOn(Schedulers.computation())
4
.observeOn(AndroidSchedulers.mainThread())
5
.subscribe(new Observer<AppInfo>() { [...]
Copied!
用这几行代码,我们将可以快速关掉Navigation Drawer,一个漂亮的进度条,一个工作在独立的线程缓慢执行的计算任务,并在主线程返回结果让我们更新已安装的应用列表。
Copy link