Android开发打造万能的适配器

阅读更多

     有过一定项目开发经验的人们都知道Android里的listView在项目里使用的很频繁。这样我们要定义各式各样重复工作的Adapter,这是很蛋疼的。于是重写Adapter是可以精简项目的代码。

     传统的Adapter

     主xml文件



    

     item.xml每个条目



    
 
 
  
   

        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 mDatas;
   
    /**
     *
     */
    public MyAdapter(Context context,List 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(R.id.idTitle);
            holder.mDesc=(TextView) convertView.findViewById(R.id.idDesc);
            holder.mTime=(TextView) convertView.findViewById(R.id.idTime);
            holder.mPhone=(TextView) convertView.findViewById(R.id.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 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();
        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(R.id.listView);
    }
}

 

2、以上就是传统的写法,是不是觉得很不爽,一个项目有多少个实体类啊,要自定义这么多的Adapter,冗余的代码太多了,

       《1》、adpter里的控件持有者的内部类Viewholder,可以抽取出来。然后在Adapter里轻松的一句话引用就可以了:(注意:这样做效率和传统的一样,只是为了满足面向对象程序设计的原则:高内聚,低耦合)

         难点;怎么抽取了?这是个问题

          a、必须要有一个键值对的Map,提供一个整型的id,得到一个view控件。从效率上讲,使用Android提供的
SparseArray来代替。还需要BaseAdapter的getView方法形参的参数,如position,和convertview

       代码如下

/**
 * 2015年9月19日下午6:21:45
 * Administrator:Elliot
 */
public class ViewHolder {

    private SparseArray 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 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(R.id.idTitle);
         TextView tv1=holder.getView(R.id.idDesc);
         TextView tv2=holder.getView(R.id.idTime);
         TextView tv3=holder.getView(R.id.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 extends BaseAdapter {

    protected Context mContext;
   
    protected List mDatas;
    protected LayoutInflater mInflater;
   
    public CommonAdapter(Context mContext,List 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.是不是很酷。。。

 

     结合对Viewholder和BaseAdapter了继承,我们最终的代码如下:

/**
 * 2015年9月19日下午7:08:16
 * Administrator:Elliot
 */
public class MyAdapterCommon2 extends CommonAdapter {

    /**
     * @param mContext
     * @param datas
     */
    public MyAdapterCommon2(Context mContext, List 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(R.id.idTitle);
         TextView tv1=holder.getView(R.id.idDesc);
         TextView tv2=holder.getView(R.id.idTime);
         TextView tv3=holder.getView(R.id.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();
    }

}

    通过这个案例,我们在写代码时一定要具备面向对象编程的思想,灵活地应用。封装继承这些面向对象的优势,写出高质量的代码,可能有时候确实想不到这些特别爽的代码,但是还是要慢慢地向这个方向发展,生活不易,且行且珍惜吧。。。

 

 

 

你可能感兴趣的:(Android,BaseAdapter,模版,面向对象)