1.效果预览
1.1.网站列表实际界面
1.2.注意这个界面没有继承SimpleRefreshRecycleFragment
前面的话题和新闻继承了SimpleRefreshRecyclerFragment
但是网站的页面继承了第二等级的RefreshRecyclerFragment
区别就在于:
第三等级的SimpleRefreshRecyclerFragment具有快速回到顶部的功能。
其实SitesListFragment也有快速回到顶部的功能,不过和前两个不太一样。
因为布局的方式不一样,
SitesListFragment要获取一个GridLayoutManager
但是前两个要获取一个自定义的LinearLayoutManager
2.SitesListFragment整体分析
2.1.布局依旧是和前两个一样的
这是RefreshRecyclerFragment中定义的布局
所以可以知道布局是一样的
那么RecyclerView是支持多列分布的。
2.2.函数分布情况
除了newInstance函数和convertData是自己新建的函数外,其他都是override基类中的方法的。
2.3.SitesListFragment源代码

/* * Copyright 2017 GcsSloop * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Last modified 2017-04-09 14:32:41 * * GitHub: https://github.com/GcsSloop * Website: http://www.gcssloop.com * Weibo: http://weibo.com/GcsSloop */ package com.gcssloop.diycode.fragment; import android.content.Context; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import com.gcssloop.diycode.fragment.base.RefreshRecyclerFragment; import com.gcssloop.diycode.fragment.bean.SiteItem; import com.gcssloop.diycode.fragment.bean.SitesItem; import com.gcssloop.diycode.fragment.provider.SiteProvider; import com.gcssloop.diycode.fragment.provider.SitesProvider; import com.gcssloop.diycode_sdk.api.sites.bean.Sites; import com.gcssloop.diycode_sdk.api.sites.event.GetSitesEvent; import com.gcssloop.diycode_sdk.log.Logger; import com.gcssloop.recyclerview.adapter.multitype.HeaderFooterAdapter; import java.io.Serializable; import java.util.ArrayList; import java.util.List; /** * 首页 sites 列表 */ public class SitesListFragment extends RefreshRecyclerFragment<Sites, GetSitesEvent> { public static SitesListFragment newInstance() { Bundle args = new Bundle(); SitesListFragment fragment = new SitesListFragment(); fragment.setArguments(args); return fragment; } @Override public void initData(HeaderFooterAdapter adapter) { setLoadMoreEnable(true); List<Serializable> sitesList = mDataCache.getSitesItems(); if (sitesList != null) { Logger.e("sites : " + sitesList.size()); mAdapter.addDatas(sitesList); setLoadMoreEnable(false); } else { loadMore(); } } @Override protected void setAdapterRegister(Context context, RecyclerView recyclerView, HeaderFooterAdapter adapter) { mAdapter.register(SiteItem.class, new SiteProvider(getContext())); mAdapter.register(SitesItem.class, new SitesProvider(getContext())); } @NonNull @Override protected RecyclerView.LayoutManager getRecyclerViewLayoutManager() { GridLayoutManager layoutManager = new GridLayoutManager(getContext(), 2); layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { return (mAdapter.getFullDatas().get(position) instanceof SiteItem) ? 1 : 2; } }); return layoutManager; } @NonNull @Override protected String request(int offset, int limit) { return mDiycode.getSites(); } @Override protected void onRefresh(GetSitesEvent event, HeaderFooterAdapter adapter) { toast("刷新成功"); convertData(event.getBean()); } @Override protected void onLoadMore(GetSitesEvent event, HeaderFooterAdapter adapter) { toast("加载成功"); convertData(event.getBean()); } @Override protected void onError(GetSitesEvent event, String postType) { toast("获取失败"); } // 转换数据 private void convertData(final List<Sites> sitesList) { ArrayList<Serializable> items = new ArrayList<>(); for (Sites sites : sitesList) { items.add(new SitesItem(sites.getName())); for (Sites.Site site : sites.getSites()) { items.add(new SiteItem(site.getName(), site.getUrl(), site.getAvatar_url())); } if (sites.getSites().size() % 2 == 1) { items.add(new SiteItem("", "", "")); } } mAdapter.clearDatas(); mAdapter.addDatas(items); mDataCache.saveSitesItems(items); setLoadMoreEnable(false); } }
3.SitesListFragment局部分析
3.1.新建一个实例
这个不解释了,args其实没有数据,可能是为了方便,直接copy的。
3.2.初始化initData
这是基类中最后执行的方法。
这里的作用:判断缓存中有没有网站数据。如果有,直接加到adapter中,如果没有执行RefreshRecyclerFragment
中的loadMore()方法,loadMore主要是进行request请求,然后确定请求状态数据等。
3.3.注册数据类型
这里和其他不一样,这里注册了两个类,所以了解一下这两个类。
SiteItem==>
然后是SitesItem==>
SiteItem有:name,url,avater_url
SitesItem有:name
都是自定义的Bean类。
3.4.获取布局管理器
这里的布局采用了GridLayoutManager==>格子分布,包括两列。
也许这里才是关键的布局设置。
3.5.请求函数
获取网站数据。
3.6.刷新数据
这里调用BaseFragment中的toast函数
然后调用convertData函数
终于理解了。这个items其实是所有的站点的集合。
因为这个SitesListFragment分了几个大模块。
每个模块中可能是奇数个,如果是奇数个,就添加一个空的接下去。
其中每个模块也是用了一个for循环遍历了sites中的getSites。
所以这个sitesList就是遍历模块的种类。
然后这个sites.getSites就是遍历每一个模块中的站点。
3.7. 加载更多
同样调用了数据转换的函数。
3.8.获取失败
4.总结一下
4.1.懂得这个SiteItem和SiteItems的区别,其实这是两个不同的类,看到实际的界面之后理解了。因为首先有多个模块。
然后模块中是具体的某些站点,这个站点其实就是SiteItem包括了名字,url,头像,这个模块其实就是SiteItems
仅仅展示一些名称就好,类别名称。
4.2.这里的初始化数据要理解一下,这里首先从缓存中得到一个sitesList,其实这个sitesList就是所有的站点+模块类别,
因为这两个类很相似,一个叫做SiteItem,一个叫做SitesItem,在注册数据类型的时候,应该就是如果数据对应
的是SiteItem,采用某一种布局,然后如果数据对应是SitesItem,就采用另外一种布局。
4.3.在关键函数convertData数据转换中,首先就变量模块个数,每个模块都加到一个ArrayList<Serializable>,很明
显,SitesItem和SiteItem是不同类型的,但是都实现Serializable,所以都可以采用items.add的方式添加到这个
集合中。值得注意的是,如果某个类别有奇数个,那么用一个空的填充到尾巴。
4.4.然后是一个getRecyclerViewLayoutManager函数,因为这个SiteListFragment没有继承第三等级的封装类,所以
要自己写一个获取布局管理器的函数。这里将布局分成了2部分了,然后调用了一个setSpanSizeLookup来判断
应该执行那个布局。以后再详细了解。