Android之ListView的高级封装!

在任何项目中ListView无疑是用得最多的Android原生控件之一,ListView的使用方法、复用ConvertView、以及ViewHolder的使用这里就不再赘述了。

本文想要谈谈的是,当项目中反复使用到ListView时,如何对ListView进行封装,简化重复代码,提高效率。

class MyAdapter extends BaseAdapter {
		@Override
		public int getCount() {
			return data.size();
		}
		@Override
		public Object getItem(int position) {
			return data.get(position);
		}
		@Override
		public long getItemId(int position) {
			return position;
		}
		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			ViewHolder holder;
			if(convertView == null){
				holder = new ViewHolder();
				// 1.加载布局文件
				View view = View.inflate(context, R.layout.listviewitem, null);
				// 2.初始化控件
				holder.textView = view.findViewById(R.id.textView1);
				// 3.打一个tag标记
				view.setTag(holder);
			}else{
				holder = (ViewHolder) convertView.getTag();
			}
			 	// 4.设置数据刷新内容
			holder.textView.setText("设置内容");
			return convertView;
		}
    }

    static class ViewHolder {
    	TextView textView;
    }


上面贴出的代码,就是我们很常见的ListView写法。但是假如在一个项目当中,如果很多地方都要用到ListView的话,那么你就不断的需要重写BaseAdapter的四个方法,以及一个ViewHolder。所以,我们就想着把ListView和ViewHolder封装起来,写成一个MyBaseHolder和MyBaseAdapter。

但是如何封装呢?封装BaseAdapter最需要注意的方法就是getView()方法,但是我们可以看到,它一般的就是4个目的:

  1. 加载布局文件
  2. 初始化控件
  3. 打一个tag标记
  4. 设置ListView的item数据


具体封装好的额两个MyBaseHolder和MyBaseAdapter直接先贴出来如下:

public abstract class MyBaseHolder<T> {
	// 一个item的根布局
	private View mRootView;
	// 一个item的数据
	private T data;

	// 当new这个对象时, 就会加载布局, 初始化控件,设置tag
	public MyBaseHolder() {
		mRootView = initView();
		// 3. 打一个标记tag
		mRootView.setTag(this);
	}
	// 1. 加载布局文件
	// 2. 初始化控件 findViewById
	public abstract View initView();
	// 返回item的布局对象
	public View getRootView() {
		return mRootView;
	}
	// 设置当前item的数据
	public void setData(T data) {
		this.data = data;
		refreshView(data);
	}
	// 获取当前item的数据
	public T getData() {
		return data;
	}
	// 4. 根据数据来刷新界面
	public abstract void refreshView(T data);
}


 
 
public abstract class MyBaseAdapter<T> extends BaseAdapter {

	private ArrayList<T> data;

	public MyBaseAdapter(ArrayList<T> data) {
		this.data = data;
	}
	@Override
	public int getCount() {
		return data.size();
	}
	@Override
	public T getItem(int position) {
		return data.get(position);
	}
	@Override
	public long getItemId(int position) {
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		MyBaseHolder<T> baseHolder;
		if(convertView == null){
			// 1. 加载布局文件
			// 2. 初始化控件 findViewById
			// 3. 打一个标记tag
			baseHolder = getHolder();
		}else{
			baseHolder = (MyBaseHolder<T>) convertView.getTag();
		}
		// 4. 设置内容刷新界面
		baseHolder.setData(getItem(position));
		return baseHolder.getRootView();
	}

	public abstract MyBaseHolder<T> getHolder();
}

 写完这两个类后,以后再用到ListView时,只要写一个具体的类继续MyBaseHolder(),这里我写一个Demo示范一下: 

假设我的ListView里的item就是一个TextView,那么可以写一个ViewHolder如下:

public class SpecificHolder extends MyBaseHolder<String> {

	private TextView mTextView;

	@Override
	public View initView() {
		// 1. 加载布局
		View view = View.inflate(null, R.layout.item_listview, null);
		// 2. 初始化控件
		mTextView = (TextView) view.findViewById(R.id.textView1);
		return view;
	}

	@Override
	public void refreshView(String data) {
		// 3. 设置内容刷新界面
		mTextView.setText(data);
	}

}


那么最先贴出来的代码就可以改成如下了:

class MyAdapter extends MyBaseAdapter<String>{

		public MyAdapter(ArrayList<String> data) {
			super(data);
		}

		@Override
		public MyBaseHolder<String> getHolder() {
			return new SpecificHolder();
		}
    	
    }

 


也许你已经乱了,我也是怕以后搞不清了就写个博客来加深记忆,也方便以后回忆。

我们来看下代码执行过程来一下:
  1. 当有一个ListView设置的Adapter是继承我们封装好的MyBaseAdapter之后,然后ListView在内部肯定会走到MyBaseAdapter的getView()方法中,
  2. 在getView()方法里会调用getHolder()方法,由于这个方法是抽象的,会调用具体子类实现的getHolder()方法;
  3. 在子类的实现的具体getHolder()方法中,它会new出一个继承了我们的MyBaseHolder类的具体的类,就是上述的SpecificHolder 类。
  4. 当他new出这个类时,就会在父类MyBaseHolder的构造方法中,调用initView()方法,储存这个ListView的item的布局,并找到这个布局当中的控件,同时给这个布局打了一个Tag。也就是完成了上文提到的getView()方法目的的前3个;
  5. 然后执行getView()方法中baseHolder.setData(getItem(position));这一句代码。它就会在MyBaseHolder的setData()方法中执行refreshView(data)方法;
  6. 由于refreshView(data)方法也是抽象的,所以它会走到自己写的SpecificHolder 类的refreshView(data)方法中,由保存的布局控件设置传递过来的数据data,此时完成了第4个目的。
  7. 最后getView()方法返回储存在holder的item的布局,结束。


在上述整个对ListView的封装当中,对数据的不确定用到了泛型,因为ListView里具体展示的内容是不确定的。
就说到这吧,如果有疑问就私信吧!



  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值