Android开发中,向服务器请求一个列表并显示是非常常见的需求,但实现起来比较麻烦,代码繁杂。

随着应用的更新迭代,这种需求越来越多,我渐渐发现了实现这种需求的代码的共同点。

于是我将Activity中http列表请求和加载的相同功能代码提取出来,作为这种Activity的基类,名为BaseHttpListActivity。

之后将缓存功能也集成在BaseHttpListActivity中,然后还根据业务需求衍生出了BaseHttpListFragment。

后来又有了从本地数据库加载列表的需求,就再次从BaseHttpListActivity提取出了BaseListActivity,负责列表显示和缓存。

BaseHttpListActivity只负责http请求,通过继承BaseHttpListActivity来实现显示和缓存。

有了BaseHttpListActivity和BaseHttpListFragment,原来用于实现http列表请求、加载和缓存的代码就变得非常简单了。

比如以下这个界面的主页:

列表是一个UserListFragment,支持下拉刷新上拉加载,第一次进入会直接显示刷新动画并加载数据。

 /**用户列表界面fragment
* @author Lemon
* @use new UserListFragment(),详细使用见.DemoFragmentActivity(initData方法内)
* @must 查看 .HttpManager 中的@must和@warn
* 查看 .SettingUtil 中的@must和@warn
*/
public class UserListFragment extends BaseHttpListFragment<User, UserAdapter>
implements OnItemClickListener, OnCacheCallBack<User> {
// private static final String TAG = "UserListFragment"; //与Activity通信<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< public static final String ARGUMENT_RANGE = "ARGUMENT_RANGE"; //与Activity通信>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> public static final int RANGE_ALL = HttpRequest.USER_LIST_RANGE_ALL;
public static final int RANGE_RECOMMEND = HttpRequest.USER_LIST_RANGE_RECOMMEND; private int range = RANGE_ALL;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState); argument = getArguments();
if (argument != null) {
range = argument.getInt(ARGUMENT_RANGE, range);
} initCache(this); //功能归类分区方法,必须调用<<<<<<<<<<
initView();
initData();
initListener();
//功能归类分区方法,必须调用>>>>>>>>>> lvBaseList.onRefresh(); return view;
} //UI显示区(操作UI,但不存在数据获取或处理代码,也不存在事件监听代码)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @Override
public void initView() {//必须调用
super.initView(); } @Override
public void setList(final List<User> list) {
setList(list, new AdapterCallBack<UserAdapter>() { @Override
public void refreshAdapter() {
adapter.refresh(list);
} @Override
public UserAdapter createAdapter() {
return new UserAdapter(context, list);
}
});
} //UI显示区(操作UI,但不存在数据获取或处理代码,也不存在事件监听代码)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> //data数据区(存在数据获取或处理代码,但不存在事件监听代码)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @Override
public void initData() {//必须调用
super.initData(); } @Override
public void getListAsync(final int pageNum) {
HttpRequest.getUserList(range, pageNum, 0, this);
} @Override
public List<User> parseArray(String json) {
return Json.parseArray(json, User.class);
} @Override
public Class<User> getCacheClass() {
return User.class;
}
@Override
public String getCacheGroup() {
return "range=" + range;
}
@Override
public String getCacheId(User data) {
return data == null ? null : "" + data.getId();
} //data数据区(存在数据获取或处理代码,但不存在事件监听代码)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> //listener事件监听区(只要存在事件监听代码就是)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @Override
public void initListener() {//必须调用
super.initListener(); lvBaseList.setOnItemClickListener(this);
} //系统自带监听方法 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
position -= lvBaseList.getHeaderViewsCount();
if (position < 0 || adapter == null || position >= adapter.getCount()) {
return;
} User user = adapter.getItem(position);
if (BaseModel.isCorrect(user)) {//相当于 user != null && user.getId() > 0
toActivity(UserActivity.createIntent(context, user.getId()));
}
} //类相关监听<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< //类相关监听>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> //系统自带监听方法>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> //listener事件监听区(只要存在事件监听代码就是)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> //内部类,尽量少用<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< //内部类,尽量少用>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> }

getListAsync用于请求服务器列表数据,setList用于显示列表数据,

parseArray用于将服务器返回的json串转化为一个List<User>的方法。

通过initCache(this);初始化缓存,得到getCacheClass,getCacheGroup,getCacheId这3个缓存方法。

range相关代码是为了传入一个用户范围(或类型),让服务器返回需要范围的数据。

listener事件监听区代码里实现了点击列表项跳转至用户详情界面的功能。

剩下onCreateView和3个init方法维持着这个Fragment的框架。

原来Activity和Fragment中实现同样功能的上千行代码竟然能简化成这样!!!

而且如果是Fragment,有一个XListView默认布局,连layout都不再需要写了!!!

如果只需要从服务器加载一个列表,缓存和事件相关代码就可以去掉了;如果不需要限定数据范围,还可以去掉range相关代码。

 /**用户列表界面fragment
* @author Lemon
* @use new UserListFragment(),详细使用见.DemoFragmentActivity(initData方法内)
* @must 查看 .HttpManager 中的@must和@warn
* 查看 .SettingUtil 中的@must和@warn
*/
public class UserListFragment extends BaseHttpListFragment<User, UserAdapter> {
// private static final String TAG = "UserListFragment"; @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState); //功能归类分区方法,必须调用<<<<<<<<<<
initView();
initData();
initListener();
//功能归类分区方法,必须调用>>>>>>>>>> lvBaseList.onRefresh(); return view;
} //UI显示区(操作UI,但不存在数据获取或处理代码,也不存在事件监听代码)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @Override
public void setList(final List<User> list) {
setList(list, new AdapterCallBack<UserAdapter>() { @Override
public void refreshAdapter() {
adapter.refresh(list);
} @Override
public UserAdapter createAdapter() {
return new UserAdapter(context, list);
}
});
} //UI显示区(操作UI,但不存在数据获取或处理代码,也不存在事件监听代码)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> //data数据区(存在数据获取或处理代码,但不存在事件监听代码)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @Override
public void getListAsync(final int pageNum) {
HttpRequest.getUserList(0, pageNum, 0, this);
} @Override
public List<User> parseArray(String json) {
return Json.parseArray(json, User.class);
} //data数据区(存在数据获取或处理代码,但不存在事件监听代码)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> //listener事件监听区(只要存在事件监听代码就是)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< //类相关监听<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< //类相关监听>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> //系统自带监听方法>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> //listener事件监听区(只要存在事件监听代码就是)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> //内部类,尽量少用<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< //内部类,尽量少用>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> }

是不是更简洁了呢?

BaseHttpListActivity和BaseHttpListFragment已开源,依赖ZBLibrary(含使用方法)就可使用,下方附下载地址。

ZBLibrary-Android快速开发框架

下载地址(欢迎Star,欢迎Fork)

https://github.com/TommyLemon/Android-ZBLibrary

下载试用

ZBLibraryDemoApp.apk

BaseHttpListActivity,几行代码搞定Android Http列表请求、加载和缓存的更多相关文章

  1. 30行代码搞定WCF并发性能测试

    [以下只是个人观点,欢迎交流] 30行代码搞定WCF并发性能 轻量级测试. 1. 调用并发测试接口 static void Main()         {               List< ...

  2. 10行代码搞定移动web端自定义tap事件

    发发牢骚 移动web端里摸爬滚打这么久踩了不少坑,有一定移动web端经验的同学一定被click困扰过.我也不列外.一路走来被虐的不行,fastclick.touchend.iscroll什么的都用过, ...

  3. Android艺术——Bitmap高效加载和缓存代码分析(2)

    Bitmap的加载与缓存代码分析: 图片的压缩 比如有一张1024*768像素的图像要被载入内存,然而最终你要用到的图片大小其实只有128*96,那么我们会浪费很大一部分内存,这显然是没有必要的,下面 ...

  4. Android艺术——Bitmap高效加载和缓存(1)

    通过Bitmap我们可以设计一个ImageLoader,实现应该具有的功能是: 图片的同步加载:图片的异步加载:图片的压缩:内存缓存:磁盘缓存:网络获取: 1.加载 首先提到加载:BitmapFact ...

  5. [Unity Editor]10行代码搞定Hierarchy排序

    在日常的工作和研究中,当给我们的场景摆放过多的物件的时候,Hierarchy面板就会变得杂乱不堪.比如这样:    过多的层次结构充斥在里面,根层的物件毫无序列可言,整个层次面板显示非常的杂乱不堪,如 ...

  6. Tensorflow快餐教程(1) - 30行代码搞定手写识别

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/lusing/article/details ...

  7. 如何用Python统计《论语》中每个字的出现次数?10行代码搞定--用计算机学国学

    编者按: 上学时听过山师王志民先生一场讲座,说每个人不论干什么,都应该学习国学(原谅我学了计算机专业)!王先生讲得很是吸引我这个工科男,可能比我的后来的那些同学听课还要认真些,当然一方面是兴趣.一方面 ...

  8. AlloyTouch实战--60行代码搞定QQ看点资料卡

    原文链接:https://github.com/AlloyTeam/AlloyTouch/wiki/kandian 先验货 访问DEMO你也可以点击这里 源代码可以点击这里 如你体验所见,流程的滚动的 ...

  9. GJM : AlloyTouch实战--60行代码搞定QQ看点资料卡

    原文链接:https://github.com/AlloyTeam/AlloyTouch/wiki/kandian 先验货 访问DEMO你也可以点击这里 源代码可以点击这里 如你体验所见,流程的滚动的 ...

随机推荐

  1. linux常用命令汇总

    1. 文件及文件夹操作 1.1 修改文件名 mv abc ab 把文件名abc改为ab. 1.2 删除文件和文件夹 rm abc rm -rf abc 1.3 拷贝文件夹 格式: CP [选项]  源 ...

  2. adnroid 监听软键盘的显隐

    首先注明出处,我只是想做个笔记:http://www.jb51.net/article/64820.htm 第一眼看到的时候,觉得不太可靠,因为之前都是看到这样处理的,根据监听一个根布局的size,可 ...

  3. 欧拉回路(hdu3018)

    刚学图论不久,看着别人的博客慢慢学了一点基础的,感觉还是有点力不从心,感觉图论的题好多长得都很像,什么太监算法(Tarjan),Kosaraju,当然最基础的还是并查集...好了继续介绍这道题.... ...

  4. ASP.NET MVC bootstrap 3 ie 8兼容问题及错误解决(取消IE禁用IE脚本调试定位js文件错误)

    因要做一个B/S架构的项目,使用MVC框架技术,本人不擅长页面设计美工,只好用bootstrap框架,在chrome内核系列的浏览器和IE 11中显示都没有问题,但是在 IE 8下显示却不正常,表格无 ...

  5. caffe + ubuntu16.04 (version without GPU)

    This Guide is based on caffe github wiki guide (https://github.com/BVLC/caffe/wiki/Ubuntu-16.04-or-1 ...

  6. URL编码和解码工具

    开发中发现需要进行URL的编解码,每次百度出来的还带广告而且比较慢,写了一个本地的工具,比较简单,希望对大家有帮助. <!DOCTYPE html PUBLIC "-//W3C//DT ...

  7. MultipeerConnectivity框架,近场通信的基本使用

    Multipeer connectivity是一个使附近设备通过Wi-Fi网络.P2P Wi-Fi以及蓝牙个人局域网进行通信的框架.互相链接的节点可以安全地传递信息.流或是其他文件资源,而不用通过网络 ...

  8. 【javascript】作用域和闭包浅析

    作用域 分全局作用域和局部作用域 全局作用域:函数外部定义的变量,可以被整个program的各成员参照利用. 局部作用域:函数内部定义的变量,仅供该函数的各成员参照利用. var val=1; //全 ...

  9. python3 装饰器

    #Author by Andy#_*_ coding:utf-8 _*_#装饰器的原则及构成:# 原则:# 1.不能修改被装饰函数的源代码.# 2.不能修改被装饰函数的调用方式.# 3.不能改变被装饰 ...

  10. C#快捷键

    home:光标所在这一行的最前面 end:光标所在这一行的最后面 pg up:光标所在这一页最前一行的前面 pg dn:光标所在这一页最后一行的最后 shift+home:光标所在这一行之前的所有代码 ...