在我們的第一個列子里,我們將檢索安裝的應(yīng)用列表并填充RecycleView的item來展示它們。我們也設(shè)想一個下拉刷新的功能和一個進(jìn)度條來告知用戶當(dāng)前任務(wù)正在執(zhí)行。
首先,我們創(chuàng)建Observable。我們需要一個函數(shù)來檢索安裝的應(yīng)用程序列表并把它提供給我們的觀察者。我們一個接一個的發(fā)射這些應(yīng)用程序數(shù)據(jù),將它們分組到一個單獨(dú)的列表中,以此來展示響應(yīng)式方法的靈活性。
private Observable<AppInfo> getApps(){
return Observable.create(subscriber -> {
List<AppInfoRich> apps = new ArrayList<AppInfoRich>();
final Intent mainIntent = new Intent(Intent.ACTION_MAIN,null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> infos = getActivity().getPackageManager().queryIntentActivities(mainIntent, 0);
for(ResolveInfo info : infos){
apps.add(new AppInfoRich(getActivity(),info));
}
for (AppInfoRich appInfo:apps) {
Bitmap icon = Utils.drawableToBitmap(appInfo.getIcon());
String name = appInfo.getName();
String iconPath = mFilesDir + "/" + name;
Utils.storeBitmap(App.instance, icon,name);
if (subscriber.isUnsubscribed()){
return;
}
subscriber.onNext(new AppInfo(name,iconPath,appInfo.getLastUpdateTime()));
}
if (!subscriber.isUnsubscribed()){
subscriber.onCompleted();
}
});
}
AppInfo對象如下:
@Data
@Accessors(prefix = "m")
public class AppInfo implements Comparable<Object> {
long mLastUpdateTime;
String mName;
String mIcon;
public AppInfo(String nName, long lastUpdateTime, String icon) {
mName = nName;
mIcon = icon;
mLastUpdateTime = lastUpdateTime;
}
@Override
public int compareTo(Object another) {
AppInfo f = (AppInfo)another;
return getName().compareTo(f.getName());
}
}
需要重點(diǎn)注意的是在發(fā)射新的數(shù)據(jù)或者完成序列之前要檢測觀察者的訂閱情況。這樣的話代碼會更高效,因?yàn)槿绻麤]有觀察者等待時我們就不生成沒有必要的數(shù)據(jù)項(xiàng)。
此時,我們可以訂閱Observable并觀察它。訂閱一個Observable意味著當(dāng)我們需要的數(shù)據(jù)進(jìn)來時我們必須提供對應(yīng)的操作來執(zhí)行它。
當(dāng)前的場景是什么?我們展示一個進(jìn)度條來等待數(shù)據(jù)。當(dāng)數(shù)據(jù)到來時,我們需要隱藏掉進(jìn)度條,填充list,最終展示列表?,F(xiàn)在,我們知道當(dāng)一切都準(zhǔn)備好了該做什么。那么錯誤的場景呢?對于錯誤這種情況,我們僅僅是用Toast展示一個錯誤的信息。
使用Butter Knife,我們得到list和下拉刷新組件的引用:
@InjetcView(R.id.fragment_first_example_list)
RecyclerView mRecycleView;
@InjectView(R.id.fragment_first_example_swipe_container)
SwipeRefreshLayout mSwipeRefreshLayout;
我們使用Android 5的標(biāo)準(zhǔn)組件:RecyclerView和SwipeRefreshLayout。截屏展示了我們這個簡單App的list Fragment的layout文件:
http://wiki.jikexueyuan.com/project/rxjava/images/chapter3_4.png" alt="" />
我們使用一個下拉刷新方法,因此列表數(shù)據(jù)可以來自初始化加載,或由用戶觸發(fā)的一個刷新動作。針對這兩個場景,我們用同樣的行為,因此我們把我們的觀察者放在一個易被復(fù)用的函數(shù)里面。下面是我們的觀察者,定義了成功、失敗、完成要做的事情:
private void refreshTheList() {
getApps().toSortedList()
.subscribe(new Observer<List<AppInfo>>() {
@Override
public void onCompleted() {
Toast.makeText(getActivity(), "Here is the list!", Toast.LENGTH_LONG).show();
}
@Override
public void onError(Throwable e) {
Toast.makeText(getActivity(), "Something went wrong!", Toast.LENGTH_SHORT).show();
mSwipeRefreshLayout.setRefreshing(false);
}
@Override
public void onNext(List<AppInfo> appInfos) {
mRecyclerView.setVisibility(View.VISIBLE);
mAdapter.addApplications(appInfos);
mSwipeRefreshLayout.setRefreshing(false);
}
});
}
定義一個函數(shù)使我們能夠用同樣一個block來處理兩種場景成為了可能。當(dāng)fragment加載時我們只需調(diào)用refreshTheList()方法并設(shè)置refreshTheList()方法作為用戶下拉這一行為所觸發(fā)的方法。
mSwipeRefreshLayout.setOnRefreshListener(this::refreshTheList);
我們第一個例子現(xiàn)在完成了,運(yùn)行跑一下。
http://wiki.jikexueyuan.com/project/rxjava/images/chapter3_5.png" alt="" />