没有看过上一篇文章的话,建议先去阅读GooglePlay:9.代码抽取(adapter)
项目框架的搭建:
以后每个view都是holder
BaseHolder
-
public abstract class BaseHolder<Data> {//写data和t一样 private View contentView; private Data data; protected BitmapUtils bitmapUtils; public BaseHolder(){ bitmapUtils = BitmapHelper.getBitmapUtils(); contentView=initView(); contentView.setTag(this); } /** 创建界面*/ public abstract View initView(); public View getContentView() { return contentView; } public void setData(Data data){ this.data=data; refreshView(data); } /** 根据数据刷新界面*/ public abstract void refreshView(Data data); }
MoreHolder
-
public class MoreHolder extends BaseHolder<Integer> { public static final int HAS_NO_MORE=0; // 没有额外数据了 public static final int LOAD_ERROR=1;// 加载失败 public static final int HAS_MORE=2;// 有额外数据 private RelativeLayout rl_more_loading,rl_more_error; /**当Holder显示的时候 显示什么样子*/ @Override public View initView() { View view=UiUtils.inflate(R.layout.load_more); rl_more_loading=(RelativeLayout) view.findViewById(R.id.rl_more_loading); rl_more_error=(RelativeLayout) view.findViewById(R.id.rl_more_error); return view; } private DefaultAdapter adapter; public MoreHolder(DefaultAdapter adapter) { super(); this.adapter=adapter; } @Override public View getContentView() { loadMore(); return super.getContentView(); } private void loadMore() { // 请求服务器 加载下一批数据 // 交给Adapter 让Adapter 加载更多数据 adapter.loadMore(); } /**根据数据做界面的修改*/ @Override public void refreshView(Integer data) { rl_more_error.setVisibility(data==LOAD_ERROR?View.VISIBLE:View.GONE); rl_more_loading.setVisibility(data==HAS_MORE?View.VISIBLE:View.GONE); } }
DefaultAdapter :
多种不同类型条目的ListView
-
public abstract class DefaultAdapter<Data> extends BaseAdapter { protected List<Data> datas; private static final int DEFAULT_ITEM = 0; private static final int MORE_ITEM = 1; public List<Data> getDatas() { return datas; } public void setDatas(List<Data> datas) { this.datas = datas; } public DefaultAdapter(List<Data> datas) { this.datas = datas; } @Override public int getCount() { return datas.size() + 1; // 最后的一个条目 就是加载更多的条目 } @Override public Object getItem(int position) { return datas.get(position); } /** 根据位置 判断当前条目是什么类型 */ @Override public int getItemViewType(int position) { //20 if (position == datas.size()) { // 当前是最后一个条目 return MORE_ITEM; } return getInnerItemViewType(position); // 如果不是最后一个条目 返回默认类型 } private int getInnerItemViewType(int position) { return DEFAULT_ITEM; } /** 当前ListView 有几种不同的条目类型 */ @Override public int getViewTypeCount() { return super.getViewTypeCount() + 1; // 2 有两种不同的类型 } @Override public long getItemId(int position) { return position; } public View getView(int position, View convertView, ViewGroup parent) { BaseHolder holder = null; switch (getItemViewType(position)) { // 判断当前条目时什么类型 case MORE_ITEM: if(convertView==null){ holder=getMoreHolder(); }else{ holder=(BaseHolder) convertView.getTag(); } break; case DEFAULT_ITEM: if (convertView == null) { holder = getHolder(); } else { holder = (BaseHolder) convertView.getTag(); } if (position < datas.size()) { holder.setData(datas.get(position)); } break; } return holder.getContentView(); // 如果当前Holder 恰好是MoreHolder 证明MoreHOlder已经显示 } private MoreHolder holder; private BaseHolder getMoreHolder() { if(holder!=null){ return holder; }else{ holder=new MoreHolder(this); return holder; } } protected abstract BaseHolder<Data> getHolder(); /** * 当加载更多条目显示的时候 调用该方法 */ public void loadMore() { ThreadManager.getInstance().createLongPool().execute(new Runnable() { @Override public void run() { // 在子线程中加载更多 final List<Data> newData = onload(); UiUtils.runOnUiThread(new Runnable() { @Override public void run() { if(newData==null){ holder.setData(MoreHolder.LOAD_ERROR);// }else if(newData.size()==0){ holder.setData(MoreHolder.HAS_NO_MORE); }else{ // 成功了 holder.setData(MoreHolder.HAS_MORE); datas.addAll(newData);// 给listView之前的集合添加一个新的集合 notifyDataSetChanged();// 刷新界面 } } }); } }); } /** * 加载更多数据 */ protected abstract List<Data> onload(); }
修改8的代码
SubjectFragment
-
public class SubjectFragment extends BaseFragment { private List<SubjectInfo> datas; @Override public View createSuccessView() { BaseListView listView=new BaseListView (UiUtils.getContext()); listView.setAdapter(new SubjectAdapter(datas)); return listView; } private class SubjectAdapter extends DefaultAdapter<SubjectInfo>{ public SubjectAdapter(List<SubjectInfo> datas) { super(datas); } @Override protected BaseHolder<SubjectInfo> getHolder() { return new SubjectHolder(); } @Override protected List<SubjectInfo> onload() { SubjectProtocol protocol=new SubjectProtocol(); List<SubjectInfo> load = protocol.load(0); datas.addAll(load); return load; } } class SubjectHolder extends BaseHolder<SubjectInfo>{ ImageView item_icon; TextView item_txt; @Override public View initView() { View contentView=UiUtils.inflate(R.layout.item_subject); this.item_icon=(ImageView) contentView.findViewById(R.id.item_icon); this.item_txt=(TextView) contentView.findViewById(R.id.item_txt); return contentView; } @Override public void refreshView(SubjectInfo data) { this.item_txt.setText(data.getDes()); bitmapUtils.display(this.item_icon, HttpHelper.URL+"image?name="+data.getUrl()); } } @Override protected LoadResult load() { SubjectProtocol protocol=new SubjectProtocol(); datas = protocol.load(0); return checkData(datas); } }
都是首页、APP、游戏页面很相似,所有又可以抽取
ListBaseHolder
public class ListBaseHolder extends BaseHolder<AppInfo> {
ImageView item_icon;
TextView item_title,item_size,item_bottom;
RatingBar item_rating;
public void refreshView(AppInfo data){
this.item_title.setText(data.getName());// 设置应用程序的名字
String size=Formatter.formatFileSize(UiUtils.getContext(), data.getSize());
this.item_size.setText(size);
this.item_bottom.setText(data.getDes());
float stars = data.getStars();
this.item_rating.setRating(stars); // 设置ratingBar的值
String iconUrl = data.getIconUrl(); //http://127.0.0.1:8090/image?name=app/com.youyuan.yyhl/icon.jpg
// 显示图片的控件
bitmapUtils.display(this.item_icon, HttpHelper.URL+"image?name="+iconUrl);
}
@Override
public View initView() {
View contentView=View.inflate(UiUtils.getContext(), R.layout.item_app, null);
this.item_icon=(ImageView) contentView.findViewById(R.id.item_icon);
this.item_title=(TextView) contentView.findViewById(R.id.item_title);
this.item_size=(TextView) contentView.findViewById(R.id.item_size);
this.item_bottom=(TextView) contentView.findViewById(R.id.item_bottom);
this.item_rating=(RatingBar) contentView.findViewById(R.id.item_rating);
return contentView;
}
}
ListBaseAdapter
-
public abstract class ListBaseAdapter extends DefaultAdapter<AppInfo> { public ListBaseAdapter(List<AppInfo> datas) { super(datas); } @Override protected BaseHolder<AppInfo> getHolder() { return new ListBaseHolder(); } @Override protected abstract List<AppInfo> onload(); }
GameFragment
public class GameFragment extends BaseFragment {
private List<AppInfo> datas;
/**
* 加载成功的界面
*/
@Override
public View createSuccessView() {
BaseListView listView=new BaseListView(UiUtils.getContext());
listView.setAdapter(new ListBaseAdapter(datas){
@Override
protected List<AppInfo> onload() {
GameProtocol protocol=new GameProtocol();
List<AppInfo> load = protocol.load(datas.size()); //
datas.addAll(load);
return load;
}
});
return listView;
}
/**
* 请求服务器加载数据
*/
@Override
protected LoadResult load() {
GameProtocol protocol=new GameProtocol();
datas = protocol.load(0);
return checkData(datas);
}
}
AppFragment
public class AppFragment extends BaseFragment {
private List<AppInfo> datas;
/**
* 当加载成功的时候 显示的界面
*/
@Override
public View createSuccessView() {
BaseListView listView=new BaseListView(UiUtils.getContext());
listView.setAdapter(new ListBaseAdapter(datas){
@Override
protected List<AppInfo> onload() {
AppProtocol protocol=new AppProtocol();
List<AppInfo> load = protocol.load(0);
datas.addAll(load);
return load;
}
});
return listView;
}
/**
* 请求服务器 获取服务器的数据
*/
protected LoadResult load() {
AppProtocol protocol=new AppProtocol();
datas = protocol.load(0);
return checkData(datas); // 检查数据 有三种结果 成功, 错误,空
}
}
首页有个几张图片的展示栏,所以又是一个holder
HomePictureHolder (自动轮询)
public class HomePictureHolder extends BaseHolder<List<String>> {
/* 当new HomePictureHolder()就会调用该方法 */
private ViewPager viewPager;
private List<String> datas;
@Override
public View initView() {
viewPager = new ViewPager(UiUtils.getContext());
viewPager.setLayoutParams(new AbsListView.LayoutParams(
LayoutParams.MATCH_PARENT, UiUtils
.getDimens(R.dimen.home_picture_height)));//转换成dp
return viewPager;
}
/* 当 holder.setData 才会调用 */
@Override
public void refreshView(List<String> datas) {
this.datas = datas;
viewPager.setAdapter(new HomeAdapter());
viewPager.setCurrentItem(2000*datas.size());// 设置起始的位置 Integer.Max_Vlue/2,这样开始位置也能向后划了
viewPager.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
runTask.stop();
break;
// 事件的取消,有可能按下viewpager滑动到listview上停止就不轮播了
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
runTask.start();
break;
}
return false; // viewPager 触摸事件 返回值要是false
}
});
runTask = new AuToRunTask();
runTask.start();
}
boolean flag;
private AuToRunTask runTask;
//Runnable并不是开启子线程,所以可以在主线程运行,thread才是开启线程
public class AuToRunTask implements Runnable{
@Override
public void run() {
if(flag){
UiUtils.cancel(this); // 取消之前
int currentItem = viewPager.getCurrentItem();
currentItem++;
viewPager.setCurrentItem(currentItem);
// 延迟执行当前的任务
UiUtils.postDelayed(this, 2000);// 递归调用
}
}
public void start(){
if(!flag){
UiUtils.cancel(this); // 取消之前
flag=true;
UiUtils.postDelayed(this, 2000);// 递归调用
}
}
public void stop(){
if(flag){
flag=false;
UiUtils.cancel(this);
}
}
}
class HomeAdapter extends PagerAdapter {
// 当前viewPager里面有多少个条目
LinkedList<ImageView> convertView=new LinkedList<ImageView>();
// ArrayList
@Override
public int getCount() {
return Integer.MAX_VALUE;//这样写条目就能一直划了
}
/* 判断返回的对象和 加载view对象的关系 */
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
ImageView view=(ImageView) object;
convertView.add(view);// 把移除的对象 添加到缓存集合中
container.removeView(view);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
int index=position%datas.size();//访问网络需要这个参数
ImageView view;
if(convertView.size()>0){
view=convertView.remove(0);
}else{
view= new ImageView(UiUtils.getContext());
}
bitmapUtils.display(view, HttpHelper.URL + "image?name="
+ datas.get(index));
container.addView(view); // 加载的view对象
return view; // 返回的对象
}
}
}
UiUtils 添加这三个方法
-
/** * 延迟执行 任务 * @param run 任务 * @param time 延迟的时间 */ public static void postDelayed(Runnable run, int time) { BaseApplication.getHandler().postDelayed(run, time); // 调用Runable里面的run方法 } /** * 取消任务 * @param auToRunTask */ public static void cancel(Runnable auToRunTask) { BaseApplication.getHandler().removeCallbacks(auToRunTask); } } 这样写获取到图片高的dp <dimen name="home_picture_height">134dp</dimen> public static int getDimens(int homePictureHeight) { return (int) getResource().getDimension(homePictureHeight); }
HomeFragment
public class HomeFragment extends BaseFragment {
private List<AppInfo> datas;
private List<String> pictures; // 顶部ViewPager 显示界面的数据
// 当Fragment挂载的activity创建的时候调用
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
show();
}
public View createSuccessView() {
BaseListView listView=new BaseListView(UiUtils.getContext());
HomePictureHolder holder=new HomePictureHolder();
holder.setData(pictures);
View contentView = holder.getContentView(); // 得到holder里面管理的view对象
//contentView.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
listView.addHeaderView(contentView); // 把holder里的view对象 添加到listView的上面
listView.setAdapter(new ListBaseAdapter(datas,listView){
@Override
protected List<AppInfo> onload() {
HomeProtocol protocol=new HomeProtocol();
List<AppInfo> load = protocol.load(datas.size());
datas.addAll(load);
return load;
}
@Override
public void onInnerItemClick(int position) {
super.onInnerItemClick(position);
Toast.makeText(getActivity(), "position:"+position, 0).show();
AppInfo appInfo = datas.get(position);
Intent intent=new Intent(UiUtils.getContext(), DetailActivity.class);
intent.putExtra("packageName", appInfo.getPackageName());//将包名传到详情页,详情页访问网络用包名
startActivity(intent);
}
});
// 第二个参数 慢慢滑动的时候是否加载图片 false 加载 true 不加载
// 第三个参数 飞速滑动的时候是否加载图片 true 不加载
listView.setOnScrollListener(new PauseOnScrollListener(bitmapUtils, false, true));
bitmapUtils.configDefaultLoadingImage(R.drawable.ic_default); // 设置如果图片加载中显示的图片
bitmapUtils.configDefaultLoadFailedImage(R.drawable.ic_default);// 加载失败显示的图片
return listView;
}
public LoadResult load() {
HomeProtocol protocol=new HomeProtocol();
datas = protocol.load(0); // load index 从哪个位置开始获取数据 0 20 40 60
pictures = protocol.getPictures();
return checkData(datas);
}
}
修改
DefaultAdapter,这样传调到详情页面的时候position
已经是修改过的了,我们并不希望去点首页的图片展示
-
public DefaultAdapter(List<Data> datas,ListView lv) { this.datas = datas; // 给ListView设置条目的点击事件 lv.setOnItemClickListener(this); this.lv=lv; } // ListView 条目点击事件回调的方法 @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { //Toast.makeText(UiUtils.getContext(), "position:"+position, 0).show(); position=position-lv.getHeaderViewsCount();// 获取到顶部条目的数量 位置去掉顶部view的数量 onInnerItemClick(position); } /**在该方法去处理条目的点击事件*/ public void onInnerItemClick(int position) { }
面向holder编程
-
public View createSuccessView() { BaseListView listView=new BaseListView(UiUtils.getContext()); HomePictureHolder holder=new HomePictureHolder(); holder.setData(pictures); View contentView = holder.getContentView(); // 得到holder里面管理的view对象 contentView.setLayoutParams(new AbsListView.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT)); listView.addHeaderView(contentView); // 把holder里的view对象 添加到listView的上面