程序员人生 网站导航

封装能重用的自定义Adapter,向翔哥致敬

栏目:综合技术时间:2015-06-24 07:59:35

看了翔哥的自定义万能的adapter,自己也做下笔记,分析1下高手的思惟方式,让我们1起进入变态程序员的内心世界。

分析万能的adapter之前,我们先分析1下普通的adapter

public class ReportSpinnerAdapter extends BaseAdapter { private Context context; private List<String> str; public ReportSpinnerAdapter(Context context, List<String> str, int textWidth) { this.context = context; this.str = str; this.textWidth = textWidth; } @Override public int getCount() { return str.size(); } @Override public Object getItem(int position) { return str.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { Viewholder hold; if (convertView==null){ convertView = LayoutInflater.from(context).inflate(R.layout.spinner_layout,parent,false); hold = new ViewHold(); hold.textView = (TextView) convertView.findViewById(R.id.textView); convertView.setTag(hold); }else{ hold = (ViewHold) convertView.getTag(); } hold.textView.setText(str.get(position)); return convertView; } static class ViewHolder{ TextView textView; }

普通的adapter大致就分为两点,getViewViewHolder,1个类就解决问题,触及到控件的复用,就用到了ViewHolder,主要逻辑还是都在getView中,,如果对这个不理解,可以先百度ViewHoldergetView中的逻辑就是如果convertView第1次被使用的时候,初始化绑定布局,并设置标记,否则,就从convertView取出viewHolder,如果要更改布局中控件的参数就从viewHolder中取出控件设置参数,由于这个控件在convertView初始化的时候就1起初始化了,所以直接设置参数就ok了。这是1个标准程序员的通常做法,但是,这样如果我们程序中要常常使用adapter,每一个ListviewGridView都要去弄1个adapter,就白白浪费了大量的时间,作为1个变态程序员,翔哥怎样能忍,所以就出了这么1篇博客翔哥博客,让我们也能从中获利,收获了新技术也收获了新的思惟方式。

 

总结自定义万能的adapter,或叫做可重用的adapter,分拆开来看,就是3点:

1.封装1个特殊的ViewHolder,可以传入参数就直接得到viewHolder,把这步干掉:

if (convertView==null){ convertView = LayoutInflater.from(context).inflate(R.layout.spinner_layout,parent,false); hold = new ViewHold(); hold.textView = (TextView) convertView.findViewById(R.id.textView); convertView.setTag(hold); }else{ hold = (ViewHold) convertView.getTag(); }

想要干掉这1步,就要想到,传入甚么样的参数,才能直接得到viewHolder呢,就是后面这几个,1.LayoutInflater.from(context)  2.R.layout.spinner_layout 3.parent 4.convertView

知道了需要的条件就好说了,直接写1个

public class ViewHolder { private SparseArray<View> views; private View convertView; public ViewHolder(ViewGroup parent,LayoutInflater inflater,int layoutId) { this.views = new SparseArray<View>(); this.convertView = inflater.inflate(layoutId,parent,false); this.convertView.setTag(this); } /** * 得到viewHolder * @param parent * @param convertView * @param inflater * @param layoutId * @return */ public static ViewHolder getViewHolder(ViewGroup parent,View convertView,LayoutInflater inflater,int layoutId){ if (convertView==null){ return new ViewHolder(parent,inflater,layoutId); } return (ViewHolder) convertView.getTag(); }

这个 SparseArray<View> views实际上就是1个键值对,用来保存listviewgridview上每行或每列上的所有控件的,效力上要高于hashmap,用法就是

/** * 根据Id得到view * @param viewId * @param <T> * @return */ public <T extends View>T getView(int viewId){ View view = views.get(viewId); if (view==null){ view = convertView.findViewById(viewId); views.put(viewId,view); } return (T) view; }

这样,1个ViewHolder就弄定了。

 

2.编写1个通用的adapter,通用adapter,基本没法实现,那怎样办呢,做1个半通用的adapter,既然要半通用,就是大体相同,少数差异,那用抽象类继承的方式就最好了

public abstract class CommonAdapter<T> extends BaseAdapter { private List<T> list; private LayoutInflater inflater; private int layoutId; public CommonAdapter(List<T> list, Context context,int layoutId) { this.list = list; this.inflater = LayoutInflater.from(context); this.layoutId = layoutId; } @Override public int getCount() { return list.size(); } @Override public Object getItem(int position) { return list.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder = ViewHolder.getViewHolder(parent,convertView,inflater,layoutId); convert(viewHolder,list.get(position)); return viewHolder.getConvertView(); } public abstract void convert(ViewHolder viewHolder,T t); }

首先,我们绑定adapter的时候不肯定数据源,就得用泛型类和泛型集合了,再就是传入布局idcontext上下文,把需要给控件赋值的地方设置为抽象方法,给子类继承,这样封装好了以后,我们需要做的事情就是少之又少了,只需要重写convert方法和构造方法了

public class MyAdapter extends CommonAdapter<Bean> { public MyAdapter(List<Bean> list, Context context, int layoutId) { super(list, context, layoutId); } @Override public void convert(ViewHolder viewHolder, Bean bean) { ((TextView)viewHolder.getView(R.id.text)).setText("这是测试数据1"); ((TextView)viewHolder.getView(R.id.text)).setText("这是测试数据1"); } }

这样,只需要在activityfragment中进行绑定MyAdapter,把数据和布局idcontent传入就弄定了。只不过(viewHolder.getView(R.id.text)).setText这类写法很蛋疼,代码中写强转的话,还要把光标切回来,反正我个人是很不习惯的,那怎样办呢,可以这样,我们既然有了viewholder对象,我们就改造1下viewHolder对象,让公共代码多1点,我们以后重复写的地方就少1点。在ViewHolder中加入以下方法

/** * 根据id得到TextView * @return */ public TextView getTextView(int viewId){ return getView(viewId); } /** * 根据id得到ImageView * @return */ public ImageView getImageView(int viewId){ return getView(viewId); } /** * 根据id得到Button * @return */ public Button getButton(int viewId){ return getView(viewId); } /** * 根据id得到RadioButton * @return */ public RadioButton getRadioButton(int viewId){ return getView(viewId); } /** * 根据id得到CheckBox * @return */ public CheckBox getCheckBox(int viewId){ return getView(viewId); } /** * 根据id得到ImageButton * @return */ public ImageButton getImageButton(int viewId){ return getView(viewId); } /** * 根据id得到ImageButton * @return */ public EditText getEditText(int viewId){ return getView(viewId); }

那末我们的Myadapter中的convert方法就能够这样写了

@Override public void convert(ViewHolder viewHolder, Bean bean) { viewHolder.getTextView(R.id.text).setText("这是测试数据1"); viewHolder.getTextView(R.id.text).setText("这是测试数据2"); }

这样书写起来就会流畅1点,比较跟手,好了,这基本就是翔哥万能的自定义adapter的主要内容,下面图解1下核心思想







最后,源码:点击打开链接


------分隔线----------------------------
------分隔线----------------------------

最新技术推荐