不用后悔的ListView,GridView万能适配器 - 相同,不同 行布局都能用

本文详细介绍了一种适用于ListView和GridView的万能适配器,该适配器能够显著简化代码,提高开发效率。尤其适合拥有多个ListView或GridView的复杂应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

                                ListView,GridView万能适配器   -   上

                                            (相同行布局)

        博主做了好多项目,没有一个项目敢说用不到ListView(下拉刷新ListView也算) ListView是安卓初级到安卓中级的纽带,学好ListView控件是很有必要。

        注:刚接触不同item(行布局)的可参考:

                       http://blog.csdn.net/gjy_it/article/details/52014075      (下一章,不同行布局的万能适配器)

         

         *以下几点是掌握ListView的关键:

        1.了解ListView的属性布局 常用的比如数点击改变item颜色,diliver颜色 长度等

           (具体还是百度把,毕竟互联网那么强大)

        2.ListView可以看作的MVC模型。 那么适配器就比较重要,大多数是通过适配器改             变 View的数据显示。一般很多复杂的逻辑也是在适配器里实现,因为要掌握适               配器的各种方法以及用法甚至是优化。

        3.前期可以大量练习ListView适配器的使用 ,要实践 , 实践多了,写个适配器都不               用动个脑子。

          以上都是前期掌握ListView的基本要求,那么再高一点需要:

        4.掌握ListView的适配器的优化。

        5.多种行布局的使用

        6.多种行布局 并优化

        7.解决在ListView中行布局复用导致重新显示

             (典型的例子就是  用listView  每个item进行下载

                 可参考 http://blog.csdn.net/gjy_it/article/details/52262928

                )

         8。就是越来越多的item。。。。。

       -----------------以上都是废话,不用在意那么多细节-------------

                            

        万能适配器:说万能是骗人的,但是可以优化代码以及减少很多不必要的代码。

                             确实比普通手写的适配器要节省很多时间,因此推荐使用。

         万能适配器的原理:

                      在普通的适配器中,适配器优化都通过ViewHolder来进行复用行布局。

                       控件也是申明在ViewHolder中,那么万能适配器会独立出一个类来专门                          初始化View并存储View, 最后我们还会有一个自己定义的抽象类继承于

                        BaseAdapter ,因为大多数结构需要在getView中完成 ,那么, 在                                 getView中常用到的逻辑写在自定义的抽象类的getView里, 不确定的逻                         辑通过抽象方法抽象给子类。这样就可以减少很多的代码量。

为什么要用万能适配器?

(在安卓开发中,用到ListView和GridView的地方实在是太多了,系统默认给我们提供的适配器(ArrayAdapter,SimpleAdapter)经常不能满足我们的需要,因此我们时常要去继承BaseAdapter类去实现一个自定义的适配器来满足我们的场景需要。

如果你是开发一个简单点的APP还好,可能ListView和GridView的数量不会太多,我们只要去写几个BaseAdapter实现类就可以了。

但如果有一天,你需要开发一个APP里面具有几十个ListView或者GridView的子页面,此时的你该怎么办?每个ListView或者GridView都去写一个适配的Adatper类吗?

当然你如果想做蛮牛不嫌累的话也不是不可以,但如果有办法可以让自己减少很多工作量,避免做重复无意义劳动,何乐而不为呢?


            本篇先讲  相同行布局 的用法

          (这个万能适配器比较旧版本,关注下一章会介绍功能更多的万能适配器)

             看下demo结构:

               

                 CommonAdapter.java就是自定义抽象的适配器

                 ViewHolder.java 

                 MyModel,java 测试需要 模拟数据

                 那么先来看下ViewHolder是何方神圣?

             

package com.example.ex0_listviewadapter;
import android.content.Context;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

/**
 * @author gjy
 * 
 *  通用的ViewHolder
 * 
 * **/
public class ViewHolder {

	//存放绑定的控件的容器
	private final SparseArray<View> mViews;
	//item视图
	private View mConvertView;

	private  ViewHolder(Context context,ViewGroup parent,int layoutId,int position) 
	{
		this.mViews=new SparseArray<View>();
		//初始化视图
		mConvertView=LayoutInflater.from(context).inflate(layoutId, parent,false);
		//绑定Tag
		mConvertView.setTag(this);
	}


	/**
	 *  获取Viewholder的对象  为类的入口
	 *  @param Context 上下文
	 *  @param convertview item视图
	 *  @param layoutId item布局的id
	 *  @param position 当前item的position
	 *  
	 * */
	public static ViewHolder get(Context context,View convertview,ViewGroup parent,int layoutId,int position)
	{

		if (convertview==null) {

			return new ViewHolder(context, parent, layoutId, position);
		}
		return  (ViewHolder) convertview.getTag();

	}
	/**
	 *  通过控件的id获取对于控件,如果没有加入view
	 * */
	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;
	}
	/***
	 * 为TextView 设置字符串
	 * **/
	public ViewHolder setText(int viewId,String text)
	{
		TextView view=getView(viewId);
		view.setText(text);
		return this;
	}
	/***
	 * 为ImageView 设置图片资源
	 * **/
	public ViewHolder setImageResource(int viewId,int drawableId)
	{
		ImageView img=getView(viewId);
		img.setImageResource(drawableId);
		return this;
	}
	/***
	 * 为ImageView 通过URL访问图片
	 * **/
//	public ViewHolder setImageResource(int viewId,String url)
//	{
//		ImageView img=getView(viewId);
//		UILUtils.displayImageNoAnim(url, img);
//		return this;
//	}


	public View getConvertview()
	{
		return mConvertView;
	}
}
                      解析:1.SparseArray就是稀疏数组,可以理解为HashMap,SparseArray的性能比HashMap高。

                                                              (用View对应的ID来保存View)

                                                          2.public <T extends View>T getView(int viewId) 就是通过刚刚那个SparseArray 键值 用 ID 对来 获取View

                                                                  可以理解为  View v=findViewById(ID) 通过ID获的一个View 

                                                          3..mConvertView.setTag(this); 以及getConvertview()   get() 【获取ViewHolder对象】 都封装在这个类中

                                                           4.setXXXX  就是通过对应的ID  来获取viewHolder 中绑定的控件 并为他绑定数据

                             自定义抽象类:

               

package com.example.ex0_listviewadapter;

import java.util.List;

import android.R.integer;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

public abstract class CommonAdapter<T> extends BaseAdapter {

 protected LayoutInflater mInflater;
	protected Context context;
	protected List<T> mDatas;
	protected final int mLayoutId;

         /**
	 * @param
	 * **/
	public CommonAdapter(Context context,List<T> mdaList,int mLayoutId) {

		this.context=context;
		this.mDatas=mdaList;
		this.mInflater = LayoutInflater.from(context);
		this.mLayoutId=mLayoutId;
	}
    
	@Override
	public int getItemViewType(int position) {
		// TODO Auto-generated method stub
		
		return super.getItemViewType(position);
	}

	@Override
	public int getViewTypeCount() {
		// TODO Auto-generated method stub
		return super.getViewTypeCount();
	}

	@Override
	public int getCount() {
		// TODO Auto-generated method stub
		return mDatas.size();
	}

	@Override
	public T 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 View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub

		final ViewHolder viewHolder=getViewHolder(position, convertView, parent);
		//抽象一个方法出去 方便进行实现
		convert(viewHolder, getItem(position));
 
		return viewHolder.getConvertview();
	}
	public  abstract void convert(ViewHolder helper,T item);
	private  ViewHolder getViewHolder(int position,View converView,ViewGroup parent)
	{
		return ViewHolder.get(context, converView, parent, mLayoutId, position);
	}
}

                     解析 :

                            来看下构造函数 public CommonAdapter(Context context,List<T> mdaList,int mLayoutId)    

                           来再来看下ViewHolder的构造函数ViewHolder(Context context,ViewGroup parent,int layoutId,int position) 

                                                 ---List<T> mdaList 这个数据类  是在抽象类里面的getcount 要用到 获取总数个。 那么int mLayoutId,为布局的ID

                                                  这个是要在ViewHolder中转为View的。实现BaseAdapter的方法跟普通适配器一样。

                                                   

@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		// TODO Auto-generated method stub

		final ViewHolder viewHolder=getViewHolder(position, convertView, parent);
		//抽象一个方法出去 方便进行实现
		convert(viewHolder, getItem(position));
 
		return viewHolder.getConvertview();
	}
	public  abstract void convert(ViewHolder helper,T item);
	private  ViewHolder getViewHolder(int position,View converView,ViewGroup parent)
	{
		return ViewHolder.get(context, converView, parent, mLayoutId, position);
	}
                          重点来了:

                                          getViewHolder 方法里 通过调用ViewHolder的静态方法get获取到ViewHolder的对象 

                                          最后对数据进行绑定的时候是需要用到Viewholder(因为View都是保存在ViewHolder里)

                                           最后:

                                      //抽象一个方法出去 方便进行实现

                            convert(viewHolder, getItem(position));

                                         ViewHolder 的对象以及数据  最后在抽象接口中只管对数据进行绑定就可以了。

 

                     多琢磨几次就懂了。来看下Demo:

               

@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		List<MyModel> lists=new ArrayList<MyModel>();
		for (int i = 0; i < 20; i++) {

			lists.add(new MyModel("A"+i, "B"+i,"C"+i));
		}
		ListView mListView=(ListView) findViewById(R.id.listView1);
		mListView.setAdapter(new CommonAdapter<MyModel>(MainActivity.this,lists,R.layout.item_1) {

			@Override
			public void convert(ViewHolder helper, MyModel item) {

				helper.setText(R.id.textView1, item.getTxt1());
				helper.setText(R.id.textView2, item.getTxt2());
				helper.setText(R.id.textView3, item.getTxt3());

			}
		});

	}

                                           只管在convert 里写了这么一点东西。 是不是简便了很多。

                                            


            Demo下载地址(ViewHolder中有错 删除即可)

                                     http://download.csdn.net/detail/gjy_it/9666243

        

                                 

      

                 

          

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值