废话不说了,直接进入主题...
今天上午,主要完成了:
1.加载页面:LoadingPager.java
2.模拟一些假数据(这些数据以后会通过网络链接到后台服务器获取),完成首页数据的显示
3.使用ViewHolder优化ListView,提高ListView的运行效率,并最终抽取BaseHolder
关于优化ListView的技术,不知哪位大神写的,感觉挺好的。再次谢谢他了,
这是链接: ListView中convertView和ViewHolder的工作原理
今天上午的任务比较少,就直接上代码了。每天进步一点。不积跬步,无以至千里。
先看运行效果图:
LoadingPager.java
package com.btt.ui.widget; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.widget.FrameLayout; import com.example.R; import com.example.manage.ThreadManager; import com.example.utils.UIUtils; /** * 加载页面 * 分析:每个Fragment页面都有:正在加载页面,错误页面,空页面,成功页面 * 因此这个类会动态的根据用户从服务器请求的数据的状态来选择要显示的页面 * @author bitaotao */ public abstract class LoadingPager extends FrameLayout { private static final int STATE_DEFAULT = 1;// 未知状态,也就是默认状态(加载状态) private static final int STATE_LOADING = 2;// 加载状态 private static final int STATE_EMPTY = 3;// 加载完毕,但是没有数据的状态 private static final int STATE_ERROR = 4;// 加载完毕,但是错误状态 private static final int STATE_SUCCESS = 5;// 加载成功,有数据的成功状态 private int mState;//记录当前的状态,根据状态确定显示那个页面 private View mLoadingView;//加载时显示的View private View mEmptyView;//加载没有数据显示的View private View mErrorView;//加载出错显示的View private View mSuccessView;//加载成功显示的View private void init() { setBackgroundColor(UIUtils.getColor(R.color.bg_page));//设置背景 mState = STATE_DEFAULT;//初始化状态 //创建对应的View,并添加到布局中 mLoadingView = createLoadingView(); if(null != mLoadingView){ addView(mLoadingView, new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT)); } mEmptyView = createEmptyView(); if(null != mEmptyView){ addView(mEmptyView, new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT)); } mErrorView = createErrorView(); if(null != mErrorView){ addView(mErrorView, new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT)); } //显示对应的View showSafePage(); } /**线程安全的方法*/ private void showSafePage() { UIUtils.runInMainThread(new Runnable() { @Override public void run() { showPage(); } }); } /**显示对应的View*/ protected void showPage() { if(null != mLoadingView){ mLoadingView.setVisibility(mState == STATE_DEFAULT || mState == STATE_LOADING ? View.VISIBLE : View.INVISIBLE); } if(null != mErrorView){ mErrorView.setVisibility(mState == STATE_ERROR ? View.VISIBLE : View.INVISIBLE); } if(null != mEmptyView){ mEmptyView.setVisibility(mState == STATE_EMPTY ? View.VISIBLE : View.INVISIBLE); } //只有数据成功返回了,才知道成功的View改如何显示,因为该View的显示依赖加载完毕后的数据 if(mSuccessView == null && mState == STATE_SUCCESS){ mSuccessView = createSuccessView(); addView(mSuccessView, new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT)); } if(null != mSuccessView){ mSuccessView.setVisibility(mState == STATE_SUCCESS ? View.VISIBLE : View.INVISIBLE); } } public abstract View createSuccessView(); private View createErrorView() { View view = UIUtils.inflate(R.layout.loading_page_error); view.findViewById(R.id.page_bt).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { show(); } }); return view; } public synchronized void show() { if(mState == STATE_ERROR || mState == STATE_EMPTY){ mState = STATE_DEFAULT; } if(mState == STATE_DEFAULT){ mState = STATE_LOADING; LoadTask task = new LoadTask(); ThreadManager.getLongPool().execute(task); } showSafePage(); } class LoadTask implements Runnable{ @Override public void run() { final LoadResult result = load(); UIUtils.runInMainThread(new Runnable() {//主线程改变UI @Override public void run() { //状态的改变和界面息息相关,所以需要放到主线程来赋值,保障同步性 mState = result.getValue();//根据枚举对象的返回值来改变显示的状态码 showPage(); } }); } } public enum LoadResult{ EMPTY(3),ERROR(4),SUCCESS(5); int value ; LoadResult(int value){ this.value = value; } public int getValue() { return value; } } private View createEmptyView() { return UIUtils.inflate(R.layout.loading_page_empty); } public abstract LoadResult load(); private View createLoadingView() { return UIUtils.inflate(R.layout.loading_page_loading); } public LoadingPager(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } public LoadingPager(Context context, AttributeSet attrs) { super(context, attrs); init(); } public LoadingPager(Context context) { super(context); init(); } }
package com.example.fragment; import java.util.List; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.btt.ui.widget.LoadingPager; import com.btt.ui.widget.LoadingPager.LoadResult; import com.example.utils.UIUtils; public abstract class BaseFragment extends Fragment { public LoadingPager mContentView; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if(null == mContentView){ mContentView = new LoadingPager(UIUtils.getContext()) { @Override public LoadResult load() { return BaseFragment.this.load(); } @Override public View createSuccessView() { return BaseFragment.this.createSuccessView(); } }; } return mContentView; } protected abstract View createSuccessView(); protected abstract LoadResult load(); public LoadResult check(Object obj) { if(obj == null){ return LoadResult.ERROR; } if(obj instanceof List){ List list = (List)obj; if(list.size() == 0){ return LoadResult.EMPTY; } } return LoadResult.SUCCESS; } public void show() { if(null != mContentView){ mContentView.show(); } } }
package com.example.fragment; import java.util.ArrayList; import java.util.List; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.TextView; import com.btt.ui.widget.LoadingPager.LoadResult; import com.example.holder.BaseHolder; import com.example.utils.UIUtils; public class HomeFragment extends BaseFragment { private List<String> mDatas; @Override protected View createSuccessView() { ListView mListView = new ListView(UIUtils.getContext()); HomeAdapter adapter = new HomeAdapter(); mListView.setAdapter(adapter); return mListView; } @Override protected LoadResult load() { //模拟一些假数据 mDatas = new ArrayList<String>(); for (int i = 0; i < 100; i++) { mDatas.add("我是菜鸟"+i+"号"); } return check(mDatas); } private class HomeAdapter extends BaseAdapter{ private ViewHolder holder; @Override public int getCount() { return mDatas.size(); } @Override public Object getItem(int position) { return mDatas.get(position); } @Override public long getItemId(int position) { return position; } /** * @param convertView : 这个参数用于将之前加载好的布局进行缓存,以便之后可以进行重用。 */ @Override public View getView(int position, View convertView, ViewGroup parent) { /** //目前我们的ListView的运行效率是很低的,因为在HomeAdapter的getView()方法中每次都将布局重新加载一遍。 //当ListView快速滚动的时候这就会成为性能的瓶颈 TextView tv = new TextView(UIUtils.getContext()); tv.setText(mDatas.get(position)); return tv; */ //ListView优化后的代码,提高运行效率 /** if(convertView == null){ //如果convertView为空,则使用LayoutInflater去加载布局或者创建布局 convertView = new TextView(UIUtils.getContext()); holder = new ViewHolder(); holder.tv = (TextView) convertView; convertView.setTag(holder); }else{ //如果不为空则直接对convertView进行重用,这样就大大提高了ListView的运行效率 holder = (ViewHolder) convertView.getTag(); } holder.tv.setText(mDatas.get(position)); return convertView; */ //抽取BaseHolder后的代码 if(convertView == null){ holder = new ViewHolder(); }else{ holder = (ViewHolder) convertView.getTag(); } holder.setData(mDatas.get(position)); return holder.getRootView(); } } /** * 这里我们新增了一个内部类ViewHolder,用于对控件的实例进行缓存。当convertView为空的时候,创建一个ViewHolder对象, * 并将控件的实例存放在ViewHolder里,然后调用View的setTag()方法,将ViewHolder对象存储在View中。 * 当convertView不为空的时候则调用View的getTag()方法,把ViewHolder重新取出。这样所有控件的实例都缓存在了ViewHolder里 * @author bitaotao * */ private class ViewHolder extends BaseHolder<String>{ TextView tv; @Override public void refershView() { tv.setText(getData());//将获得的数据,设置给TextView } @Override public View initView() { tv = new TextView(UIUtils.getContext()); return tv; } } }
BaseHolder.java
package com.example.holder; import android.view.View; /** * 用来缓存控件或者布局 * 因为每个ListView都有布局和填充的数据,这些都是共性,可以将布局和数据都抽取出到holder中。 * @author bitaotao * @param <T> 传递过来的数据 */ public abstract class BaseHolder<T> { private View view; private T data; public BaseHolder(){ view = initView();//初始化view view.setTag(this);//将holder对象存储在view中 } public T getData() { return data; } public void setData(T data) { this.data = data; refershView();//设置完数据之后,就重新刷新下数据,因为不知道刷新后的数据怎么显示,所以交给子类去实现 } public View getRootView(){ return view; } public abstract void refershView(); public abstract View initView(); }
ok,到此为止,去次饭了,下午再做...