哟哟哟....
项目开发第二天,这里我完成了类似“电子市场”种应用的框架的整体搭建,已经完成了,以后的开发就按照这种方法去实现。
不断地抽取,将所有的公有部分抽取出来,这样编写的代码,就很简洁,清晰,明了。
感谢传智播客提供的教学视频,让我不断学习,不断完善自己。
下午,主要完成以下功能:
1.抽取MyBaseAdapter
2.写加载更多的Holder。MoreHolder
3.模拟加载更多地数据,测试。
运行效果图:
语言是苍白的,代码是真实的。
MyBaseAdapter.java
package com.example.adapter; import java.util.List; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import com.example.holder.BaseHolder; import com.example.holder.MoreHolder; import com.example.manage.ThreadManager; import com.example.utils.UIUtils; /** * 将所有的adapter里面的holder和填充的数据抽取到MyBaseAdapter * @author bitaotao * @param <T> 需要填充的数据 */ public abstract class MyBaseAdapter<T> extends BaseAdapter { private List<T> mDatas ; private BaseHolder<T> holder; public MyBaseAdapter(List<T> mDatas) { //在构造方法里面,就将数据设置进去 setDatas(mDatas); } public List<T> getDatas() { return mDatas; } public void setDatas(List<T> mDatas) { this.mDatas = mDatas; } @Override public int getCount() { return mDatas.size() + 1;//加 1 是为了最后加载更多的布局 } @Override public Object getItem(int position) { return mDatas.get(position); } @Override public long getItemId(int position) { return position; } private final int MORE_VIEW_TYPE = 0; private final int ITEM_VIEW_TYPE = 1; private MoreHolder moreHolder; //根据position位置返回那种item展示类型 @Override public int getItemViewType(int position) { if(position == getCount() - 1){ return MORE_VIEW_TYPE;//加载更多地布局 }else{ return getItemViewTypeInner(position); } } private int getItemViewTypeInner(int position) { return ITEM_VIEW_TYPE;//普通的item的布局 } //获取item有几种类型,默认是一种类型, 这里再加1是为了做加载更多 @Override public int getViewTypeCount() { return super.getViewTypeCount() + 1;//加 1 是为了最后加载更多的布局 } @Override public View getView(int position, View convertView, ViewGroup parent) { if(null != convertView){ holder = (BaseHolder<T>) convertView.getTag(); }else{ if(MORE_VIEW_TYPE == getItemViewType(position)){ holder = getMoreHolder(); }else{ holder = getHolder(); } if(ITEM_VIEW_TYPE == getItemViewType(position)){ holder.setData(getDatas().get(position)); } } return holder.getRootView(); } private BaseHolder getMoreHolder() { if(null == moreHolder){ moreHolder = new MoreHolder(this,hasMore()); } return moreHolder; } /** * 是否有更多数据 * @return */ public boolean hasMore() { return true; } public abstract BaseHolder<T> getHolder(); private boolean is_loading = false; /** * 加载更多数据 */ public void loadMore() { //防止重复加载 if(!is_loading){ is_loading = true; ThreadManager.getLongPool().execute(new Runnable() { @Override public void run() { final List list = onLoadMore(); UIUtils.runInMainThread(new Runnable() { @Override public void run() { if(null == list){ getMoreHolder().setData(MoreHolder.ERROR); }else if(list.size() < 20){ getMoreHolder().setData(MoreHolder.NO_MORE); }else{ getMoreHolder().setData(MoreHolder.HAS_MORE); } if(null != list){ if(null != mDatas){ mDatas.addAll(list); }else{ setDatas(list); } } notifyDataSetChanged(); is_loading = false; } }); } }); } } public abstract List onLoadMore(); }
package com.example.holder; import com.example.R; import com.example.adapter.MyBaseAdapter; import com.example.utils.UIUtils; import android.view.View; import android.widget.RelativeLayout; public class MoreHolder extends BaseHolder<Integer> { // 表示跟服务器交互成功,没有更多数据类型 public static final int NO_MORE = 0;// 没有数据 // 表示跟服务器交互成功,有更多数据类型 public static final int HAS_MORE = 1;//有数据 // 表示跟服器交互失败 public static final int ERROR = 2;//错误 private MyBaseAdapter adapter; private RelativeLayout rl_more_loading,rl_more_error; public MoreHolder(MyBaseAdapter adapter, boolean hasMore) { this.adapter = adapter; setData(hasMore ? HAS_MORE : NO_MORE); } @Override public View getRootView() { if(getData() == HAS_MORE){//有更多数据,调用加载更多方法 loadMore(); } return super.getRootView(); } private void loadMore() { adapter.loadMore(); } @Override public void refershView() { Integer data = getData(); rl_more_loading.setVisibility(data == HAS_MORE ? View.VISIBLE : View.GONE); rl_more_error.setVisibility(data ==ERROR ? View.VISIBLE : View.GONE); } @Override public View initView() { View view = UIUtils.inflate(R.layout.list_more_loading); rl_more_loading = (RelativeLayout) view.findViewById(R.id.rl_more_loading); rl_more_error = (RelativeLayout) view.findViewById(R.id.rl_more_error); return view; } }
package com.example.fragment; import java.util.ArrayList; import java.util.List; import android.view.View; import android.widget.ListView; import android.widget.TextView; import com.btt.ui.widget.LoadingPager.LoadResult; import com.example.adapter.MyBaseAdapter; 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()); MyBaseAdapter adapter = new HomeAdapter(mDatas); mListView.setAdapter(adapter); return mListView; } @Override protected LoadResult load() { //模拟一些假数据 mDatas = new ArrayList<String>(); for (int i = 0; i < 30; i++) { mDatas.add("我是菜鸟"+i+"号"); } return check(mDatas); } private class HomeAdapter<T> extends MyBaseAdapter{ public HomeAdapter(List<T> mDatas) { super(mDatas); } @Override public BaseHolder getHolder() { return new ViewHolder(); } @Override public List onLoadMore() { //模拟一些要加载的假数据 List<String> moreData = new ArrayList<String>(); for (int i = 0; i < 30; i++) { moreData.add("我是更多数据"+i); } return moreData; } } /** * 这里我们新增了一个内部类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; } } }
学习总结:
上午没有总结,下午就总结在这里:
1.ListView的优化
在HomeFragment类新增一个内部类ViewHolder,用于对控件的实例进行缓存。
当convertView为空的时候,创建一个ViewHolder对象,并将控件的实例都存放在ViewHolder里,然后调用View的setTag()方法。
将ViewHolder的对象存储在View中。
当convertView不为空的时候则调用View的getTag()方法。把ViewHolder重新取出。这样所有控件的实例都缓存在了ViewHolder里,
就没有必要每次都通过findViewById()方法来获取控件实例了。
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null){
//档convertView为空时
convertView = new TextView(UIUtils.getContext());//控件的实例,这里也可以加载布局,布局中就有控件
holder = new ViewHolder();//创建ViewHolder对象,用于缓存控件
holder.tv = (TextView) convertView;//将控件或者布局的实例都存放在ViewHolder里
convertView.setTag(holder);//将ViewHolder的对象存储在View中
}else{
//convertView不为空,把ViewHolder重新取出
holder = (ViewHolder) convertView.getTag();
}
//设置数据
holder.tv.setText(mDatas.get(position));
return convertView;
}
}
public class ViewHolder{
TextView tv;
}
2.抽取BaseHolder类,采用面向holder编程。
面向ListView编程时,在使用holder优化时,就相当于我们面向holder编程了。在使用ListView编写布局时,
需要填充数据,当我们抽取holder的时候,可以将布局和数据都抽取出来,因为每个ListView都有布局和填充的数据,
这些都是共性。
public abstract class BaseHolder<T> {
private View view;
private T data;
public BaseHolder(){
view = initView();//初始化view
view.setTag(this);//将holder对象存储在view中
}
...
}
3.抽取MyBaseAdapter类,将所有的adapter里面的holder和填充的数据抽取到MyBaseAdapter
public class MyBaseAdapter<T> extends BaseAdapter {
private List<T> mDatas;
private BaseHolder<T> holder;
public MyBaseAdapter(List<T> mDatas) {
//在构造方法里面,就将数据设置进去
setmDatas(mDatas);
}
...
}
4.写MoreHolder类,用于缓存加载更多的布局和数据
这里要显示加载更多地布局,就得覆写父类中的这两个方法:
@Override
public int getItemViewType(int position) {
// TODO Auto-generated method stub
return super.getItemViewType(position);
}
@Override
public int getViewTypeCount() {
// TODO Auto-generated method stub
return super.getViewTypeCount();
}
具体详细实现请看MyBaseAdapter类和MoreHandler类