<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <ListView android:id="@+id/id_lv_main" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </RelativeLayout>
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp " > <TextView android:id="@+id/tv_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:singleLine="true" android:text="红色钱包" android:textColor="#444444" android:textSize="16sp" /> <TextView android:id="@+id/tv_desc" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/tv_title" android:layout_marginTop="10dp" android:maxLines="2" android:minLines="1" android:text="周三早上丢失了红色钱包,在食堂二楼" android:textColor="#898989" android:textSize="16sp" /> <TextView android:id="@+id/tv_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/tv_desc" android:layout_marginTop="10dp" android:text="2015-05-27 22:08:11" android:textColor="#898989" android:textSize="12sp" /> <TextView android:id="@+id/tv_phone" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_below="@id/tv_desc" android:layout_marginTop="10dp" android:background="#5cbe6c" android:drawableLeft="@drawable/icon_photo" android:drawablePadding="5dp" android:paddingBottom="3dp" android:paddingLeft="5dp" android:paddingRight="5dp" android:paddingTop="3dp" android:text="12345678901" android:textColor="@android:color/white" android:textSize="12sp" /> </RelativeLayout>
package com.owen.viewholder_commonadapter.bean; /** * 失物招领信息 * * @author owen */ public class LostInfo { private String title = null; private String desc = null; private String time = null; private String phone = null; public LostInfo() { } public LostInfo(String title, String desc, String time, String phone) { this.title = title; this.desc = desc; this.time = time; this.phone = phone; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } public String getTime() { return time; } public void setTime(String time) { this.time = time; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } }
package com.owen.viewholder_commonadapter.adapter; import java.util.List; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import com.owen.viewholder_commonadapter.R; import com.owen.viewholder_commonadapter.bean.LostInfo; public class MyAdapter extends BaseAdapter { private List<LostInfo> datas = null; private Context context = null; private LayoutInflater layoutInflater = null; public MyAdapter(Context context, List<LostInfo> datas) { this.context = context; this.datas = datas; layoutInflater = LayoutInflater.from(context); } @Override public int getCount() { return datas.size(); } @Override public Object getItem(int position) { return datas.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder = null; if (convertView == null) { viewHolder = new ViewHolder(); convertView = layoutInflater.inflate(R.layout.listview_item, parent, false); viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.tv_title); viewHolder.tvDesc = (TextView) convertView.findViewById(R.id.tv_desc); viewHolder.tvTime = (TextView) convertView.findViewById(R.id.tv_time); viewHolder.tvPhone = (TextView) convertView.findViewById(R.id.tv_phone); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } LostInfo lostInfo = (LostInfo) getItem(position); viewHolder.tvTitle.setText(lostInfo.getTitle()); viewHolder.tvDesc.setText(lostInfo.getDesc()); viewHolder.tvTime.setText(lostInfo.getTime()); viewHolder.tvPhone.setText(lostInfo.getPhone()); return convertView; } private static class ViewHolder { TextView tvTitle = null; TextView tvDesc = null; TextView tvTime = null; TextView tvPhone = null; } }
package com.owen.viewholder_commonadapter; import java.util.ArrayList; import java.util.List; import com.owen.viewholder_commonadapter.adapter.MyAdapter; import com.owen.viewholder_commonadapter.bean.LostInfo; import android.app.Activity; import android.os.Bundle; import android.widget.ListView; public class MainActivity extends Activity { private ListView listView = null; private MyAdapter adapter = null; private List<LostInfo> datas = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); populateData(); initView(); } private void populateData() { datas = new ArrayList<LostInfo>(); datas.add(new LostInfo("美女一只", "在操场捡到到一只萌萌哒妹子", "2015年5月28日 14:10:53", "123456")); datas.add(new LostInfo("谁的黑色钱包", "一餐见到的,在座位上", "2015年5月28日 14:11:01", "876545")); datas.add(new LostInfo("哆啦A梦", "哆啦A梦·伴我同行", "2015年5月28日 14:11:06", "1234567890123")); datas.add(new LostInfo("《高数上册》", "谁的高数书啊?", "2015年5月28日 14:11:10", "147852369")); } private void initView() { listView = (ListView) findViewById(R.id.listView); adapter = new MyAdapter(MainActivity.this, datas); listView.setAdapter(adapter); } }
我不想写这么多代码怎么办呢?——抽出变化的部分
那么,就需要编写一个通用的ViewHolder和Adapter
<pre name="code" class="java">package com.owen.viewholder_commonadapter.utils; import android.content.Context; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; /** * 通用的ViewHolder * * @author owen */ public class ViewHolder { /** * 存储item中所用控件引用的容器 * * Key - 资源ID * Value - 控件的引用 */ private SparseArray<View> views = null; private View convertView = null; private int position = 0; /** * 私有化的构造函数,有类内部来管理该实例 * * @param context 上下文对象 * @param itemLayoutResId item的布局文件的资源ID * @param position BaseAdapter.getView()的传入参数 * @param parent BaseAdapter.getView()的传入参数 */ private ViewHolder(Context context, int itemLayoutResId, int position, ViewGroup parent) { this.views = new SparseArray<View>(); this.position = position; this.convertView = LayoutInflater.from(context).inflate(itemLayoutResId, parent, false); convertView.setTag(this); } /** * 得到一个ViewHolder对象 * * @param context 上下文对象 * @param itemLayoutResId item的布局文件的资源ID * @param position BaseAdapter.getView()的传入参数 * @param convertView BaseAdapter.getView()的传入参数 * @param parent BaseAdapter.getView()的传入参数 * @return 一个ViewHolder对象 */ public static ViewHolder getViewHolder(Context context, int itemLayoutResId, int position, View convertView, ViewGroup parent) { if (convertView == null) { return new ViewHolder(context, itemLayoutResId, position, parent); } else { ViewHolder viewHolder = (ViewHolder) convertView.getTag(); viewHolder.position = position; // 这里要更新一下position,因为position一直发生变化 return viewHolder; } } public View getConvertView() { return convertView; } /** * 【核心部分】 * 根据控件的资源ID,获取控件 * * @param viewResId 控件的资源ID * @return 控件的引用 */ public <T extends View> T getView(int viewResId) { View view = views.get(viewResId); if (view == null) { view = convertView.findViewById(viewResId); views.put(viewResId, view); } return (T) view; } }
应用
修改一下MyAdapter.java中的getView()方法@Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder = ViewHolder.getViewHolder(context, R.layout.listview_item, position, convertView, parent); LostInfo lostInfo = (LostInfo) getItem(position); ((TextView) viewHolder.getView(R.id.tv_title)).setText(lostInfo.getTitle()); ((TextView) viewHolder.getView(R.id.tv_desc)).setText(lostInfo.getDesc()); ((TextView) viewHolder.getView(R.id.tv_time)).setText(lostInfo.getTime()); ((TextView) viewHolder.getView(R.id.tv_phone)).setText(lostInfo.getPhone()); return viewHolder.getConvertView(); }瞬间感觉简洁了很多有没有?
编写通用的Adapter
先分析一下MyAdapter可以发现有几个方法是可以重复写的其中getView()方法中
- getCount()
- getItem(int position)
- getItemId(int position)
- getView(int position ,View convertView,ViewGroup parent)
ViewHolder viewHolder = ViewHolder.getViewHolder(context, itemLayoutResId, position, convertView, parent); // 业务代码 return viewHolder.getConvertView();除了业务代码以外,都是一样的,于是考虑将业务代码抽离出来,写一个CommonAdapter<T>类,代码如下package com.owen.viewholder_commonadapter.utils; import java.util.List; import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; public abstract class CommonAdapter<T> extends BaseAdapter { /** * 数据源 */ protected List<T> datas = null; /** * 上下文对象 */ protected Context context = null; /** * item布局文件的资源ID */ protected int itemLayoutResId = 0; public CommonAdapter(Context context, List<T> datas, int itemLayoutResId) { this.context = context; this.datas = datas; this.itemLayoutResId = itemLayoutResId; } @Override public int getCount() { return datas.size(); } /** * 注意,返回值也要为泛型 */ @Override public T getItem(int position) { return datas.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder = ViewHolder.getViewHolder(context, itemLayoutResId, position, convertView, parent); convert(viewHolder, getItem(position)); return viewHolder.getConvertView(); } /** * 开发者实现该方法,进行业务处理 */ public abstract void convert(ViewHolder viewHolder, T item); }现在来修改一下MyAdapter类package com.owen.viewholder_commonadapter.adapter; import java.util.List; import android.content.Context; import android.widget.TextView; import com.owen.viewholder_commonadapter.R; import com.owen.viewholder_commonadapter.bean.LostInfo; import com.owen.viewholder_commonadapter.utils.CommonAdapter; import com.owen.viewholder_commonadapter.utils.ViewHolder; public class MyAdapter extends CommonAdapter<LostInfo> { public MyAdapter(Context context, List<LostInfo> datas, int itemLayoutResId) { super(context, datas, itemLayoutResId); } @Override public void convert(ViewHolder viewHolder, LostInfo item) { ((TextView) viewHolder.getView(R.id.tv_title)).setText(item.getTitle()); ((TextView) viewHolder.getView(R.id.tv_desc)).setText(item.getDesc()); ((TextView) viewHolder.getView(R.id.tv_time)).setText(item.getTime()); ((TextView) viewHolder.getView(R.id.tv_phone)).setText(item.getPhone()); } }发现简洁了很多,那是否还能再简洁点呢? 观察发现,有太多的setText()方法了,可以把这个方法封装到ViewHolder类中去在Viewholder类中添加一下方法public ViewHolder setText(int viewResId, String text) { TextView tv = getView(viewResId); tv.setText(text); return this; }
重新修改一下MyAdapter的convert()方法:@Override public void convert(ViewHolder viewHolder, LostInfo item) { viewHolder.setText(R.id.tv_title, item.getTitle()) .setText(R.id.tv_desc, item.getDesc()) .setText(R.id.tv_time, item.getTime()) .setText(R.id.tv_phone, item.getPhone()); }