Android-进一步封装ViewHolder
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android-进一步封装ViewHolder相关的知识,希望对你有一定的参考价值。
当我们在使用ListView或者GridView时,通常需要一个Adapter,而这个Adapter通常会继承BaseAdapter,在自定义的Adapter里面会使用ViewHolder来提高程序的效率。传统的ViewHolder模式使得程序能够提高一定的效率, 而今天我将记录一下怎么进一步的封装Adapter,使得更加的通用 -- 来自慕课网的学习
原始ViewHolder和Adapter的写法:
1 package com.example.android_commonadapter; 2 3 import android.content.Context; 4 import android.view.LayoutInflater; 5 import android.view.View; 6 import android.view.ViewGroup; 7 import android.widget.BaseAdapter; 8 import android.widget.ImageView; 9 import android.widget.TextView; 10 11 import java.util.List; 12 13 /** 14 * Created by 前世诀别的一纸书 on 2017/2/28. 15 */ 16 17 public class MyAdapter extends BaseAdapter { 18 private LayoutInflater mLayoutInflater = null; 19 private List<Bean> mDatas = null; 20 public MyAdapter(Context cotnext, List<Bean> datas) 21 { 22 mDatas = datas; 23 mLayoutInflater = LayoutInflater.from(cotnext); 24 } 25 @Override 26 public int getCount() { 27 return mDatas.size(); 28 } 29 30 @Override 31 public Object getItem(int position) { 32 return mDatas.get(position); 33 } 34 35 @Override 36 public long getItemId(int position) { 37 return position; 38 } 39 40 @Override 41 public View getView(int position, View convertView, ViewGroup parent) { 42 ViewHolder holder = null; 43 if(convertView == null) 44 { 45 holder = new ViewHolder(); 46 convertView = mLayoutInflater.inflate(R.layout.item_layout, parent, false); 47 holder.mImageView = (ImageView) convertView.findViewById(R.id.id_imageView); 48 holder.mTextViewTitle = (TextView) convertView.findViewById(R.id.id_textViewTitle); 49 holder.mTextViewContent = (TextView) convertView.findViewById(R.id.id_textViewContent); 50 convertView.setTag(holder); 51 } 52 else 53 { 54 holder = (ViewHolder) convertView.getTag(); 55 } 56 Bean bean = mDatas.get(position); 57 holder.mImageView.setImageResource(bean.mImageViewIcon); 58 holder.mTextViewTitle.setText(bean.mTextViewTitle); 59 holder.mTextViewContent.setText(bean.mTextViewContent); 60 return convertView; 61 } 62 private class ViewHolder 63 { 64 public ImageView mImageView = null; 65 public TextView mTextViewTitle = null; 66 public TextView mTextViewContent = null; 67 } 68 }
从这个原始的写法,可以看出一个Adapter只能被一个ListView所用,同时一个ViewHolder只能被一个Adapter所用,代码的重用性太低了。
1.定义通用的ViewHolder
1 package com.example.android_commonadapter; 2 3 import android.content.Context; 4 import android.util.SparseArray; 5 import android.view.LayoutInflater; 6 import android.view.View; 7 import android.view.ViewGroup; 8 9 /** 10 * Created by 前世诀别的一纸书 on 2017/2/28. 11 */ 12 13 public class ViewHolder { 14 private int mPosition = 0; 15 private View mConvertView = null; 16 private SparseArray<View> mViews; 17 18 19 20 private ViewHolder(Context context, ViewGroup parent, int layoutId, int position) { 21 mPosition = position; 22 mViews = new SparseArray<>(); 23 mConvertView = LayoutInflater.from(context).inflate(R.layout.item_layout, parent, false); 24 mConvertView.setTag(this); 25 } 26 public static ViewHolder get(Context context, ViewGroup parent, int layoutId, int position, View convertView) 27 { 28 if(convertView == null) 29 { 30 return new ViewHolder(context, parent, layoutId, position); 31 } 32 else 33 { 34 ViewHolder holder = (ViewHolder) convertView.getTag(); 35 holder.mPosition = position; 36 return holder; 37 } 38 } 39 public <T extends View> T getView(int viewId) 40 { 41 View view = mViews.get(viewId); 42 if(view == null) 43 { 44 view = mConvertView.findViewById(viewId); 45 mViews.put(viewId, view); 46 } 47 return (T) view; 48 } 49 public View getConvertView() 50 { 51 return mConvertView; 52 } 53 }
从上面的代码中,要注意几点:
1、通常我们使用Map来存储每一个控件,对应的key则是view的id。如果我们在安卓中,key是int类型,value是Object类型的话,则可以SparseArray类来代替Map,因为SparseArray是效率比Map更高。
2、在我们重用ViewHolder的时候,一定要更新ViewHolder的position, 比如上述代码中的35行。
3、getView方法则是根据View的id来获取View控件。
定义了通用的ViewHoler,我们在Adapter中只需要这样使用就行。
1 Bean bean = mDatas.get(position); 2 com.example.android_commonadapter.ViewHolder viewHolder = com.example.android_commonadapter.ViewHolder.get(mContext, parent, R.layout.item_layout, position, convertView); 3 ((ImageView)viewHolder.getView(R.id.id_imageView)).setImageResource(bean.mImageViewIcon); 4 ((TextView)viewHolder.getView(R.id.id_textViewTitle)).setText(bean.mTextViewTitle); 5 ((TextView)viewHolder.getView(R.id.id_textViewContent)).setText(bean.mTextViewContent); 6 return viewHolder.getConvertView();
2.定义通用的Adapter
首先我们定义一个抽象类,继承BaseAdapter,然后实现一些必须的方法;
其次,我们在定义一个我们自己的Adapter继承这个抽象类,实现该实现的方法。
1 package com.example.android_commonadapter; 2 3 import android.content.Context; 4 import android.view.View; 5 import android.view.ViewGroup; 6 import android.widget.BaseAdapter; 7 8 import java.util.List; 9 10 /** 11 * Created by 前世诀别的一纸书 on 2017/2/28. 12 */ 13 14 public abstract class CommonAdapter<T> extends BaseAdapter{ 15 protected List<T> mDatas = null; 16 protected Context mContext = null; 17 public CommonAdapter(Context context, List<T> datas) 18 { 19 mDatas = datas; 20 mContext = context; 21 } 22 @Override 23 public int getCount() { 24 return mDatas.size(); 25 } 26 27 @Override 28 public T getItem(int position) { 29 return mDatas.get(position); 30 } 31 32 @Override 33 public long getItemId(int position) { 34 return position; 35 } 36 37 @Override 38 public View getView(int position, View convertView, ViewGroup parent) { 39 ViewHolder viewHolder = ViewHolder.get(mContext, parent, R.layout.item_layout, position, convertView); 40 convert(getItem(position), viewHolder); 41 return viewHolder.getConvertView(); 42 } 43 protected abstract void convert(T t, ViewHolder viewHolder); 44 }
定义自己的Adapter,继承抽象类
1 public class MyAdapter2 extends CommonAdapter<Bean> { 2 public MyAdapter2(Context context, List datas) { 3 super(context, datas); 4 } 5 6 @Override 7 protected void convert(Bean bean, ViewHolder viewHolder) { 8 ((ImageView)viewHolder.getView(R.id.id_imageView)).setImageResource(bean.mImageViewIcon); 9 ((TextView)viewHolder.getView(R.id.id_textViewTitle)).setText(bean.mTextViewTitle); 10 ((TextView)viewHolder.getView(R.id.id_textViewContent)).setText(bean.mTextViewContent); 11 } 12 }
3.Item抢占焦点
当我们在在ListView的每一个Item里面加一个CheckBox,会发现Item不能点击,而CheckBox却能点击,这是为什么呢?
那是因为CheckBox抢占了焦点,解决办法就是:1、在CheckBox上面设置Android:focusable = false; 2、在父布局上设置 android:descendantFocusability="beforeDescendants"
以上是关于Android-进一步封装ViewHolder的主要内容,如果未能解决你的问题,请参考以下文章
android 怎么在外面拿recyclerview 中viewholder的控件
[Android] Android RecycleView和ListView 自定义Adapter封装类
android 打造ListView和Gridview万能adapter适配器(附源码)
int android.support.v7.widget.RecyclerView$ViewHolder.mItemViewType' on a null.....