开源项目AndroidReview学习小结(2)
读书破万卷下笔如有神
作为入门级的android码农的我,还是需要多多研读开源代码
下面继续接着上一篇的分析,这一篇主要介绍第一个tab,ReviewFragment的分析,界面看起来简单,背后的逻辑处理还是有很多值得学习的地方的。主要有下几点
- 下拉刷新
- 不同状态的页面
- 数据缓存
- 一些细节
下拉刷新
下拉刷新常见的有俩大类,Android-PullToRefresh和android-Ultra-Pull-To-Refresh 前者是国外的一大神写的出现的比较早,不过好像已经停止维护了,后者是国内的一个大神写的功能很强大,这个项目使用的是后者(MaterialHeader类型刷新),首先这里又封装了一层BasePutToRefreshFragment 用来进行下拉刷新的操作
下面简单介绍下这个控件的使用,首先是布局文件中fragment_review.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.vv.androidreview.ui.view.LoadingLayout
android:id="@+id/ly_loading"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<in.srain.cube.views.ptr.PtrFrameLayout
android:id="@+id/layout_refresh"
xmlns:cube_ptr="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#fff"
cube_ptr:ptr_duration_to_close="200"
cube_ptr:ptr_duration_to_close_header="1000"
cube_ptr:ptr_keep_header_when_refresh="true"
cube_ptr:ptr_pull_to_fresh="false"
cube_ptr:ptr_ratio_of_header_height_to_refresh="1.2"
cube_ptr:ptr_resistance="1.7">
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:cacheColorHint="#00000000"
android:divider="@color/list_divider"
android:dividerHeight="1px"
android:fadingEdge="none"
android:fastScrollEnabled="false"
android:footerDividersEnabled="false"
android:headerDividersEnabled="false"
android:scrollbars="none"
android:smoothScrollbar="true"/>
</in.srain.cube.views.ptr.PtrFrameLayout>
</RelativeLayout>
在BasePutToRefreshFragment.java中的initDoRefreshView()中开始使用该控件
private void initDoRefreshView() {
//ptr控件的使用
mPtrFrameLayout = (PtrFrameLayout) mRootView.findViewById(R.id.layout_refresh);
// header
MaterialHeader header = new MaterialHeader(getContext());
int[] colors = getResources().getIntArray(R.array.google_colors);
header.setColorSchemeColors(colors);
header.setLayoutParams(new PtrFrameLayout.LayoutParams(-1, -2));
header.setPadding(0, (int) TDevice.dpToPixel(15), 0, (int) TDevice.dpToPixel(10));
header.setPtrFrameLayout(mPtrFrameLayout);
mPtrFrameLayout.setLoadingMinTime(1000);
mPtrFrameLayout.setDurationToCloseHeader(1500);
mPtrFrameLayout.setHeaderView(header);
mPtrFrameLayout.addPtrUIHandler(header);
mPtrFrameLayout.setPinContent(true);
mPtrFrameLayout.disableWhenHorizontalMove(true);
mPtrFrameLayout.setPtrHandler(new PtrHandler() {
@Override
public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {
return PtrDefaultHandler.checkContentCanBePulledDown(frame, mListView, header);
}
@Override
public void onRefreshBegin(final PtrFrameLayout frame) {
Logger.e("list is load data by net");
//先判断是否是自动刷新
if (frame.isAutoRefresh()) {
if (mPtrFrameLayout.isRefreshing()) {
mPtrFrameLayout.refreshComplete();
}
//加载刷新布局
mLoadingLayout.setLoadingLayout(LoadingLayout.NETWORK_LOADING);
}
sPutUpState = PULL_UP_STATE_NONE;
// 这里做下拉刷新操作
requestDataByNet(REFRESH_TYPE_PULL);
}
});
}
详细的使用可以参见如下链接详细使用 不过使用开源项目还是需要尽量搞清楚其中实现的机制。
这里有俩个关键函数
- mLoadingLayout.setLoadingLayout(LoadingLayout.NETWORK_LOADING);
加载刷新布局,这在下面会介绍 - requestDataByNet(REFRESH_TYPE_PULL);
网络请求数据,这里还指明了类型用来区分是上拉还是下拉,在这个基类中将这个方法声明为抽象方法留在继承类中实现
public abstract void requestDataByNet(int actionType);
- listview的高效加载
通常的方式就是在滑动进行监听 onScrollStateChanged方法中对不同状态判断其中主要有三个状态
SCROLL_STATE_FLING,SCROLL_STATE_TOUCH_SCROLL,SCROLL_STATE_IDLE,一般是在滑动停止时(SCROLL_STATE_IDLE)才加载listview的数据
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
//在滑动停止时加载
case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
if (isItemfullScreen) {
if (sPutUpState == PULL_UP_STATE_NONE && isLoadMore) {
Logger.e("list is load more data");
pullUpLoadData();
}
}
break;
}
}
若要实现listview的加载更多还需要重写onScroll方法,这里通过一个标志位isItemfullScreen来标识
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
//firstVisibleItem -屏幕上显示的第一个item
//visibleItemCount -屏幕上一共显示item的数目
//totalItemCount -目前listview 一共有多少个itme
if (totalItemCount > visibleItemCount) {
isItemfullScreen = true;
} else {
isItemfullScreen = false;
}
}
其中加载更多需要重新定义一个布局,利用listview.addFooterView(layout)来实现,
不同状态的页面
这个非常常见,比如没有网络时页面显示一个样式,正在刷新显示一个样式,在上面的下来刷新中已经体现在mLoadingLayout.setLoadingLayout(LoadingLayout.NETWORK_LOADING); 可以看出,这种需求的实现是通过定义一个自定义控件protected LoadingLayout mLoadingLayout;,该自定义控件通过add(view)方式将自己加到页面中,其中在容器(viewgroup子类)中增加布局使用add,在widget中使用set这个要注意。这个控件会根据当前传入的状态通过switch来选择自己展现的状态,具体在LoadingLayout.java中,比较简单就不贴代码了。
这里通过单独控件的形式将各类状态分离出来,比较好操作
数据缓存
核心思想是通过序列化将数据存入到file文件中
- 读取缓存,核心类ReadCacheAsyncTask
读取是在ReviewFragment中进行处理的,首先实现了BasePutToRefreshFragment.java中的抽象方法public abstract void readCache();该方法作在fragment创建时候会调用。
- 存储缓存,核心类
SaveCacheAsyncTask
存储是在下来刷新具体实现时调用,在请求数据requestPointByUnits中
其中使用CacheHelper.java中的readObject和saveObject与之配合使用。
首先这俩个核心类的名称就可以看出这是使用AsynTask来进行处理,为了防止内存泄漏,这里都做了弱引用
先来看存储缓存
public class SaveCacheAsyncTask extends AsyncTask<Void, Void, Void> {
private WeakReference<Context> mContext;
private Serializable seri;
private String cacheKey;
public SaveCacheAsyncTask(Context context, Serializable seri, String cacheKey) {
mContext = new WeakReference<Context>(context);
this.seri = seri;
this.cacheKey = cacheKey;
}
@Override
protected Void doInBackground(Void... params) {
CacheHelper.saveObject(mContext.get(), seri, cacheKey);
return null;
}
}
其中CacheHelp中的saveObject就是做了一下存储
public static boolean saveObject(Context context, Serializable ser,
String file) {
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
fos = context.openFileOutput(file, Context.MODE_PRIVATE);
oos = new ObjectOutputStream(fos);
oos.writeObject(ser);
oos.flush();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
try {
oos.close();
} catch (Exception e) {
}
try {
fos.close();
} catch (Exception e) {
}
}
}
同理保存过程原理一致,关键在于CacheHelp中的判断是否缓存失效函数,根据文件的两次时间戳比对是否失效,在DetailActvity中选择是否沿用缓存
/**
* 判断缓存是否已经失效
*/
public static boolean isCacheDataFailure(Context context, String cachefile) {
File data = context.getFileStreamPath(cachefile);
if (!data.exists()) {
return false;
}
long existTime = System.currentTimeMillis() - data.lastModified();
boolean failure = false;
if (TDevice.getNetworkType() == TDevice.NETTYPE_WIFI) {
failure = existTime > Settings.getInt(Settings.CACHE_OVERTIME_WIFI,30) * 60 * 1000 ? true : false;
} else {
failure = existTime > Settings.getInt(Settings.CACHE_OVERTIME_OTHER,2) * 24 * 60 * 60 * 1000 ? true : false;
}
return failure;
}
一些细节
这个tab使用时listview中嵌套gridview的方式,这里就需要重写gridview的onMreasure的高度否则就会显示不全,重写也比较简单
public class GridViewEx extends GridView {
public GridViewEx(Context context) {
this(context, null);
}
public GridViewEx(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public GridViewEx(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
ok,写不动了额
开源项目AndroidReview学习小结(2)的更多相关文章
- 开源项目AndroidReview学习小结(1)
多看多学涨姿势 最近学习了一个开源项目,感觉收获颇多,这里做下简要的记录,首先感谢作者的开源.先看个大概图 感觉框架非常简单,界面也很一般,不过底层的处理的一些处理还是有很多可圈可点之处,代码的处理一 ...
- Android 开源项目及其学习
Android 系统研究:http://blog.csdn.net/luoshengyang/article/details/8923485 Android 腾讯技术人员博客 http://hukai ...
- 开源项目live555学习心得
推荐:伊朗美女找丈夫比找工作难女人婚前一定要看清三件事 × 登录注册 疯狂少男-IT技术的博客 http://blog.sina.com.cn/crazyboyzhaolei [订阅][手机订 ...
- 一个toolkit或者一个开源项目如何学习它并使用它
一个toolkit或者一个开源项目如何学习它并使用它 一般一个流行的toolkit和开源项目,一般都会被广泛地被应用: 那么,我们如何学习它,如何应用它在自己的业务场景中呢? 答案就是:学习源码并借鉴 ...
- iOS及Mac开源项目和学习资料【超级全面】
UI 下拉刷新 EGOTableViewPullRefresh – 最早的下拉刷新控件. SVPullToRefresh – 下拉刷新控件. MJRefresh – 仅需一行代码就可以为UITable ...
- iOS开发--iOS及Mac开源项目和学习资料
文/零距离仰望星空(简书作者)原文链接:http://www.jianshu.com/p/f6cdbc8192ba著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. 原文出处:codecl ...
- Android开源项目SlidingMenu学习(二)
前一篇SlidingMenu学习(一)文章中了解了导入SlidingMenu到我们项目经常出现的问题,下面我们正式学习. 先看一个效果: 看到两幅图片的差别了吗,左边的一栏时可以滑动的,可以隐藏掉,现 ...
- 分享海量 iOS 及 Mac 开源项目和学习资料
UI 下拉刷新 EGOTableViewPullRefresh - 最早的下拉刷新控件. SVPullToRefresh - 下拉刷新控件. MJRefresh - 仅需一行代码就可以为UITable ...
- Github搭建属于自己的开源项目-androd学习之旅(72)
Github是一个基于的git的版本控制工具,分为私人代码管理和开源代码管理,下面我们简单的介绍一下 首先登陆官网https://github.com 完成注册,随后首页会有四个模块,第一个是安装的指 ...
随机推荐
- Windows平台下的多线程编程
线程是进程的一条执行路径,它包含独立的堆栈和CPU寄存器状态,每个线程共享所有的进程资源,包括打开的文件.信号标识及动态分配的内存等.一个进程内的所有线程使用同一个地址空间,而这些线程的执行由系统调度 ...
- tomcat配置集群
在Tomcat中使用集群功能相对简单.最简单的用法是直接在server.xml文件的或节点下添加 <Cluster className="org.apache.catalina.ha. ...
- Dynamics CRM 2015 Online Update1 UI界面的更新变化
听说出 Dynamics CRM 2015 Online Update1了,立马跑去申请了个30天试用版简单的看了下,UI上的变化还是让人耳目一新的,也可能是被CRM2013的UI蹂躏太久了没 ...
- JSP自定义简单标签入门之带有属性
上面写的那个简单标签来控制页面中标签内容的重复次数是固定的,这就是权限"写死了",这是非常不好的行为,因为其灵活性太差.所以下面就介绍一种使用属性来控制标签内容输出次数的方法. 准 ...
- ASP.NET遇到HTTP 错误 403.14 - Forbidden Web 服务器被配置为不列出此目录的内容
当碰到这个问题的时候真的是让人很费解啊,就算是重新打开机器也不能够解决,但是下面的小技巧说不一定就可以解决这个问题了. 首先,打开IIS(Internet信息管理服务器),找到"功能&quo ...
- Torch的安装和学习
Long long ago, 就已经安装好Torch,这里再记录一下.Torch是Facebook开发的用于AI的科学计算框架,可广泛运用于机器学习的很多算法.相比Caffe,其接口运用更加方便,使用 ...
- Socket层实现系列 — 信号驱动的异步等待
主要内容:Socket的异步通知机制. 内核版本:3.15.2 我的博客:http://blog.csdn.net/zhangskd 概述 socket上定义了几个IO事件:状态改变事件.有数据可读事 ...
- Linux信号实践(5) --时间与定时器
三种不同精度的睡眠 1.sleep #include <unistd.h> unsigned int sleep(unsigned int seconds); RETURN VALUE Z ...
- DFS迷宫递归所有路径 新手入门
这篇文章写给自己以后复习和个个入门朋友:提示同学们一定耐心看完解释 哪怕看得很难受,我是新手我懂大家的心烦.看完后慢慢体会代码 我们假设迷宫为如下状况: {0,0,1,0} ...
- css之盒子模型案例
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...