(注:由于手机号验证问题,n6323438的博文转移至此)
链接: https://github.com/qijitech/android-starter-kit
Fragment系列:
(一)View与Presenter
(二)NetworkFragment
(三)RecyclerFragment之UI部分
(四)RecyclerFragment之网络部分
上一篇文章讲到了UI部分, 这次来看看网络部分.
PaginatorEmitter
上一篇文章提到, 在buildFragConfig方法里, 会new 一个PaginatorEmitter, 先看看PaginatorEmitter
public PaginatorEmitter(StarterFragConfig fragConfig, Action1<PaginatorEmitter<E>> onRequest) {
this.mFragConfig = fragConfig;
this.currentPage = fragConfig.getStartPage();
resetPaginatorKey();
this.onRequest = onRequest;
this.hasMoreData = true;
this.isLoading = true;
}
先看构造方法, 传入参数 (StarterFragConfig fragConfig, Action1<PaginatorEmitter<E>> onRequest) :
1: 把fragConfig保存起来, 内部变量currentPage等于fragConfig.getStartPage(),这个默认值是1
2: onRequest保存起来, 内部变量hasMoreData和isLoading设为true
3: 通过fragConfig判断是通过分页还是key获取数据, 这里涉及到2个内部变量:String firstPaginatorKey, nextPaginatorKey. 如果是分页, 这2个变量为currentPage; 如果是key, 那就为null
构造完成
等等,有个疑惑, 刚才内部变量isLoading设为true, 但我们并没有看到发起网络请求啊. 看看Fragment的onResume方法就明白了,
@Override public void onResume() {
super.onResume();
if (isNotNull(mPaginatorEmitter) && !mPaginatorEmitter.requested()) {
getPresenter().request();
}
}
可以看出每次onResume的时候, 就会进行网络请求.
现在来看看PaginatorEmitter中重要的内部变量 ArrayList<E> requestedItems.
这个变量放的是:从第一个id/第一页开始, 网络请求获取到的所有数据.
在onResume里, 会调用paginatorEmitter.requested()来判断, 其实就是判断requestedItems是否为空, 如果为空,那就开始网络请求. 那么一开始的时候这个requestedItems肯定是空的, 所以在onResume里就会发起第一个网络请求了.
onSuccess
再来看Fragment的onSuccess:
@Override public void onSuccess(PaginatorContract<E> paginatorContract) {
ArrayList<? extends Entity> items = paginatorContract.items();
if (mPaginatorEmitter.isFirstPage()) {
mAdapter.clear();
}
if (items == null) { // handle null
items = Lists.newArrayList();
}
mAdapter.appendAll(items);
mPaginatorEmitter.received(paginatorContract);
if (isNotNull(mPaginate)) {
mPaginate.setHasMoreDataToLoad(false);
}
if (isAdapterEmpty(mAdapter)) {
getContentPresenter().displayEmptyView();
} else {
getContentPresenter().displayContentView();
}
}
1 首先也是判断requestedItems是否为空, 如果为空, 说明是第一次获取, 就会把recyclerViewAdapter清空. (这个功能对应于下拉刷新, 因为下拉刷新肯定要把原来的数据清除). 然后把获取到的数据append进去.
2 然后调用mPaginatorEmitter.received(paginatorContract), (这个paginatorContract是对获取的数据的包装).
进去received方法: 先把isLoading设为false, 把paginatorContract保存起来, 然后判断paginatorContract是否为空, 如果为空, 说明已经获得全部数据了, hasMoreData设为false. 如果不为空, 再看如果hasMoreData本身是true, 还是true; 否则就要看获取到的数据等不等于perpage(分页大小), 来判断还有没有更多数据. 最后, 涉及到2个内部变量:firstPaginatorKey和nextPaginatorKey, firstPaginatorKey设为requestItems的第一个的id, nextPaginatorKey设为最后一个的id.这2个变量就是用在PaginatorPresenter的request方法的那2个参数.
总的来看, 这个received方法干了2件事:判断是否获取了全部数据和保存下一页从哪里开始的信息
3 mPaginate.setHasMoreDataToLoad(false) 这个方法的参数如果为true, 那就显示那个上拉加载更多的圈圈; 为false就隐藏.
4 最后判断现在的recyclerView是不是空的, 如果是空的, 就用contentPresenter显示emptyView.
onSuccess完成.
onError
再看onError:
1 调用mPaginatorEmitter.received(null), 这个表示已经获取全部数据
2 剩下的和onSuccess很类似, 这里就不说了.
上拉加载更多
接下来就要来看上拉加载更多的实现: 前面我们提到, 当recyclerView滑动到需要加载的位置时, 会调用isLoading和hasLoadedAllItems这2个方法来看要不要发起网络请求, 这2个方法在StarterRecyclerFragment实现的.
先看isLoading方法: 判断mPaginatorEmitter的isLoading 和 swipeRefreshLayout的isRefreshing, 只要其中一个满足, 就会返回true.
这个设计是为了解决 多次滑到底部导致发起多次重复的网络请求 这个问题.
再看hasLoadedAllItems方法: 判断mPaginatorEmitter的hasMoreData.
这2个方法都通过, 就到onLoadMore方法了, 经过一堆的双保险判断, 就会显示显示那个上拉加载更多的圈圈, 并发起网络请求.
上拉加载更多到此结束.
下拉刷新
下拉刷新其实就是SwipeRefreshLayout的onRefresh方法
源码比较简单, 就不贴了.
首先判断是否正在请求, 如果正在请求, 那就显示SwipeRefreshLayout自带的进度条.
如果不是, 那就重置PaginatorEmitter, 然后进行网络请求.
下一篇文章, 我会讲一下Presenter中是如何管理网络请求的.