有过一定项目开发经验的人们都知道Android里的listView在项目里使用的很频繁。这样我们要定义各式各样重复工作的Adapter,这是很蛋疼的。于是重写Adapter是可以精简项目的代码。
传统的Adapter
主xml文件
<RelativeLayout xmlns:android="http:///apk/res/android"
xmlns:tools="http:///tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/listView"/>
</RelativeLayout>
item.xml每个条目
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http:///apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14dp"
android:singleLine="true"
android:id="@+id/idTitle"
android:layout_gravity="center"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textSize="22dp"
android:id="@+id/idDesc"
/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
></LinearLayout>
<TextView
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14dp"
android:singleLine="true"
android:id="@+id/idTime"
android:gravity="center"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14dp"
android:singleLine="true"
android:id="@+id/idPhone"
android:gravity="center"
/>
</LinearLayout>
java文件
public class Bean {//getset构造函数没写,自己加
String title;
String desc;
String time;
String phone;
}
自定义的Adapter
package com.lin.imoocbaseadapter;
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.lin.adapter.bean.Bean;
/**
* 2015年9月19日下午5:42:02
* Administrator:Elliot
*/
public class MyAdapter extends BaseAdapter{
private LayoutInflater miInflater;
private List<Bean> mDatas;
/**
*
*/
public MyAdapter(Context context,List<Bean> mDatas) {
// TODO Auto-generated constructor stub
miInflater=LayoutInflater.from(context);
this.mDatas=mDatas;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return mDatas.size();
}
@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return mDatas.get(arg0);
}
@Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return arg0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
ViewHolder holder=null;
if(convertView==null){//加载布局
convertView=miInflater.inflate(R.layout.item,parent,false );
holder=new ViewHolder();
//
holder.mTitle=(TextView) convertView.findViewById(.idTitle);
holder.mDesc=(TextView) convertView.findViewById(.idDesc);
holder.mTime=(TextView) convertView.findViewById(.idTime);
holder.mPhone=(TextView) convertView.findViewById(.idPhone);
convertView.setTag(holder);
}else{//不再新建holder了
holder=(ViewHolder) convertView.getTag();
}
//完成了对holder的创建后,接下来就要给他的属性赋值了
holder.mTitle.setText(mDatas.get(position).getTitle());
holder.mDesc.setText(mDatas.get(position).getDesc());
holder.mTime.setText(mDatas.get(position).getTime());
holder.mPhone.setText(mDatas.get(position).getPhone());
return convertView;
}
private class ViewHolder{//管理getView()w的类
TextView mTitle;
TextView mDesc;
TextView mTime;
TextView mPhone;
}
}
主要看getView()方法。当convertView为null时,就新建holder对象,并且setTag记住现在的holder,下次再getView()时就不需要new Holder了。然后在给holder里的属性被view控件赋值,弄后,给view赋值,注意为String类型,否则如果为int类型的话,Android系统会认为你在找R文件的id。
MainActivity
public class MainActivity extends Activity {
private ListView listView;
private List<Bean> mDatas;
private MyAdapter myAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initDatas();
myAdapter=new MyAdapter(this, mDatas);
listView.setAdapter(myAdapter);
}
private void initDatas() {
// TODO Auto-generated method stub
mDatas=new ArrayList<Bean>();
for(int i=0;i<10;i++){
mDatas.add(new Bean("android学习"+i,"android的路上永无止境"+i,"2015-09-21","13888888888"));
}
}
private void initView() {
// TODO Auto-generated method stub
listView=(ListView) findViewById(.listView);
}
}
2、以上就是传统的写法,是不是觉得很不爽,一个项目有多少个实体类啊,要自定义这么多的Adapter,冗余的代码太多了,
《1》、adpter里的控件持有者的内部类Viewholder,可以抽取出来。然后在Adapter里轻松的一句话引用就可以了:(注意:这样做效率和传统的一样,只是为了满足面向对象程序设计的原则:高内聚,低耦合)
难点;怎么抽取了?这是个问题
a、必须要有一个键值对的Map,提供一个整型的id,得到一个view控件。从效率上讲,使用Android提供的
SparseArray<T>来代替。还需要BaseAdapter的getView方法形参的参数,如position,和convertview
代码如下
/**
* 2015年9月19日下午6:21:45
* Administrator:Elliot
*/
public class ViewHolder {
private SparseArray<View> mViews;
private int mPosition;
private View mConvertView;
public ViewHolder(Context context,ViewGroup parent,int layoutid,int position) {
// TODO Auto-generated constructor stub
mPosition=position;
mConvertView=LayoutInflater.from(context).inflate(layoutid, parent,false);
mConvertView.setTag(this);
}
//需要一个入口方法,viewHolder是通过构造方法new出来的,还是通过getTag方法得到的
public static ViewHolder get(Context context, View convertView,
ViewGroup parent, int layoutid, int position) {
if(convertView==null){
return new ViewHolder(context, parent, layoutid, position);
}else{
ViewHolder viewHolder=(ViewHolder) convertView.getTag();
viewHolder.mPosition=position;
return viewHolder;
}
}
/**
* @return the mConvertView,对外提供
*/
public View getmConvertView() {
return mConvertView;
}
//
public <T extends View> T getView(int viewId){
View view=mViews.get(viewId);
if(view==null){
view=mConvertView.findViewById(viewId);
mViews.put(viewId, view);
}
return (T) view;
}
}
此时的Adapter可以简化一下getView()方法
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
//精简了
ViewHolder holder=ViewHolder.get(mContext, convertView, parent, R.layout.item, position);
//完成了对holder的创建后,接下来就要给他的属性赋值了
TextView tv=holder.getView(.idTitle);
TextView tv1=holder.getView(.idDesc);
TextView tv2=holder.getView(.idTime);
TextView tv3=holder.getView(.idPhone);
Bean bean=mDatas.get(position);
tv.setText(bean.getTitle());
tv1.setText(bean.getDesc());
tv2.setText(bean.getTime());
tv3.setText(bean.getPhone());
return holder.getmConvertView();
}
是不是简化了一点。把三行代码简化到只有一行了。
但是还不爽,我现在还是BaseAdapter的抽象方法里除了getView()方法之外其它的三个方法,还有构造方法完全可以抽取出来吗。。。
于是呼:我们定义一个抽象类
/**
* 2015年9月19日下午6:51:59
* Administrator:Elliot
*/
public abstract class CommonAdapter<T> extends BaseAdapter {
protected Context mContext;
protected List<T> mDatas;
protected LayoutInflater mInflater;
public CommonAdapter(Context mContext,List<T> datas) {
// TODO Auto-generated constructor stub
this.mContext=mContext;
this.mDatas=datas;
mInflater=LayoutInflater.from(mContext);
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return mDatas.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return mDatas.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public abstract View getView(int position, View convertView, ViewGroup parent);
}
实现了一些抽象的方法,并且通过泛型来传递bean的不同。以后的Adapter不需要继承BaseAdapter了,都继承BaseAdapter的还在CommonAdapter<T>.是不是很酷。。。
结合对Viewholder和BaseAdapter了继承,我们最终的代码如下:
/**
* 2015年9月19日下午7:08:16
* Administrator:Elliot
*/
public class MyAdapterCommon2 extends CommonAdapter<Bean> {
/**
* @param mContext
* @param datas
*/
public MyAdapterCommon2(Context mContext, List<Bean> datas) {
super(mContext, datas);
// TODO Auto-generated constructor stub
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
//精简了
ViewHolder holder=ViewHolder.get(mContext, convertView, parent, R.layout.item, position);
//完成了对holder的创建后,接下来就要给他的属性赋值了
TextView tv=holder.getView(.idTitle);
TextView tv1=holder.getView(.idDesc);
TextView tv2=holder.getView(.idTime);
TextView tv3=holder.getView(.idPhone);
Bean bean=mDatas.get(position);
tv.setText(bean.getTitle());
tv1.setText(bean.getDesc());
tv2.setText(bean.getTime());
tv3.setText(bean.getPhone());
return holder.getmConvertView();
}
}
通过这个案例,我们在写代码时一定要具备面向对象编程的思想,灵活地应用。封装继承这些面向对象的优势,写出高质量的代码,可能有时候确实想不到这些特别爽的代码,但是还是要慢慢地向这个方向发展,生活不易,且行且珍惜吧。。。