开源项目AndroidReview学习小结(2)
2016-03-29 19:24
483 查看
读书破万卷下笔如有神
作为入门级的android码农的我,还是需要多多研读开源代码
下面继续接着上一篇的分析,这一篇主要介绍第一个tab,
下拉刷新
不同状态的页面
数据缓存
一些细节
下面简单介绍下这个控件的使用,首先是布局文件中fragment_review.xml
在BasePutToRefreshFragment.java中的
详细的使用可以参见如下链接详细使用 不过使用开源项目还是需要尽量搞清楚其中实现的机制。
这里有俩个关键函数
mLoadingLayout.setLoadingLayout(LoadingLayout.NETWORK_LOADING);
加载刷新布局,这在下面会介绍
requestDataByNet(REFRESH_TYPE_PULL);
网络请求数据,这里还指明了类型用来区分是上拉还是下拉,在这个基类中将这个方法声明为抽象方法留在继承类中实现
listview的高效加载
通常的方式就是在滑动进行监听 onScrollStateChanged方法中对不同状态判断其中主要有三个状态
若要实现listview的加载更多还需要重写onScroll方法,这里通过一个标志位isItemfullScreen来标识
其中加载更多需要重新定义一个布局,利用listview.addFooterView(layout)来实现,
这里通过单独控件的形式将各类状态分离出来,比较好操作
- 读取缓存,核心类
读取是在
存储缓存,核心类
存储是在下来刷新具体实现时调用,在请求数据
其中使用CacheHelper.java中的readObject和saveObject与之配合使用。
首先这俩个核心类的名称就可以看出这是使用AsynTask来进行处理,为了防止内存泄漏,这里都做了弱引用
先来看存储缓存
其中CacheHelp中的saveObject就是做了一下存储
同理保存过程原理一致,关键在于CacheHelp中的判断是否缓存失效函数,根据文件的两次时间戳比对是否失效,在DetailActvity中选择是否沿用缓存
ok,写不动了额
作为入门级的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,写不动了额
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories