listView 打造万能适配器

一般模板下编写一个Listview来展示数据,总共需要四个要素

  • Bean
  • Adapter
  • ViewHolder
  • ListView
  1. 主页面布局
    <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>

  2. itme的布局
    <?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>

  3. Bean
    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;
        }
    
    }

  4. Adapter
    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;
        }
    
    }

  5. MainActivity
    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);
        }
    
    }

          在项目开发中,会有很多个甚至几十个Adapter,而每个Adapter里面又要写一个配套的ViewHolder,想想就觉得头大。

          我不想写这么多代码怎么办呢?——抽出变化的部分

           那么,就需要编写一个通用的ViewHolder和Adapter

       为Adapter编写通用的Viewholder

           分析
         ViewHolder的用途有两个:
  1.  convertView.setTag(viewHolder);
  2. 存储item中所有控件的引用
          实现的难点在于 存储item中所有控件的引用。  
          但是,每个控件都有一个资源ID,所以,可不可以使用  HashMap来存储控件的引用呢?当然可以,同时,Android中提供了一个经过优化的Map,它的效率比HashMap更             高,而且它的键只能是Integer类型。

         实现

          有了核心思想,怎么实现就看自己的了
<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可以发现有几个方法是可以重复写的
  • getCount()
  • getItem(int position)
  • getItemId(int position)
  • getView(int position ,View convertView,ViewGroup parent)
其中getView()方法中
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());
}




     



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值