Android打造一个通用的BaseAdapter

作者: Android开发哥 | 来源:发表于2017-02-26 14:15 被阅读98次

    一般BaseAdapter的写法

    package com.example.august.commonadapter;
    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 java.util.List;
    /**
     * Created by August on 16/4/9.
     */
    public class MyAdapter extends BaseAdapter {
        private List<String> mDatas;
        private Context mContext;
        public MyAdapter(List<String> mDatas, Context mContext) {
            this.mDatas = mDatas;
            this.mContext = mContext;
        }
        @Override
        public int getCount() {
            return mDatas.size();
        }
        @Override
        public Object getItem(int position) {
            return mDatas.get(position);
        }
        @Override
        public long getItemId(int position) {
            return 0;
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder = null;
            if (convertView == null) {
                LayoutInflater inflater = LayoutInflater.from(mContext);
                convertView = inflater.inflate(R.layout.item_text, null);
                holder = new ViewHolder();
                holder.mTextView = (TextView) convertView.findViewById(R.id.mTextView);
                convertView.setTag(holder);
            } else {
                holder = (ViewHolder) convertView.getTag();
            }
            holder.mTextView.setText(mDatas.get(position));
            return convertView;
        }
        class ViewHolder {
            TextView mTextView;
        }
    }
    

    每次写的Adapter都写得要死,一堆都是复用的代码,下面我们就开始封装一个自己的通用Adapter,把以后的代码量尽可能减少。

    findView的时间,我们会用一个ViewHolder来保存之前查找的view.以上的Adapter思路就是给Adapter传入一个经常调用的context参数还有适配的数据,其中构造器,getCount,getItem,getItemId,几乎是一样的.然后为了减少.其中我们找出每个Adapter可能不同的内容有哪些:

    • mDatas的类型 这个简单,我们使用泛型来解决
    • 解析的Layout里面的View不确定,所以ViewHolder比较难搞

    其中第二个我们稍微比较麻烦一点,但是想想也挺简单的.想象ViewHolder就是一个容器,我们把View塞进去里面就好了.那我们就要用到容器了.好了知道用容器了,那么我们需要怎样去确定要使用哪个View呢?哈哈,也很简单,你会想到Map,key就是View的ID,value就是对应的View了.但我们这里推荐使用SparseArray容器,因为它的速度比常用的Map快多了,唯一确定就是键值只能是Integer型的,但是已经足够了...

    ViewHolder初步优化代码

    public class ViewHolder {
        private SparseArray<View> mViews;
        private View mConvertview;
        public ViewHolder(View converview) {
            this.mConvertview = converview;
            mViews = new SparseArray<View>();
        }
        public static ViewHolder getHolder(Context context, View converview, int layoutID, ViewGroup parent) {
            ViewHolder holder = null;
            if (converview == null) {
                converview = LayoutInflater.from(context).inflate(layoutID, parent, false);
                holder = new ViewHolder(converview);
                converview.setTag(holder);
            } else {
                holder = (ViewHolder) converview.getTag();
            }
            return holder;
        }
    }
    

    这样我们就可以使用getHolder方法来去新建或取回一个ViewHolder了,有了ViewHolder还不行,我们还要获取里面的View,这里我们使用泛型去写

      public <T extends View> T getView(int viewID) {
            T view = (T) mViews.get(viewID);
            if (view == null) {
                view = (T) mConvertview.findViewById(viewID);
                mViews.put(viewID, view);
            }
            return view;
        }
    

    这样以后我们就可以获取View并且作相应操作了

    GeneralParentAdapter的初步代码

    下面开始编写我们GeneralParentAdapter了,因为是通用的,所以Adapter对应的Layout就需要以参数的形式传入,mDatas也需要时泛型的.

    package com.example.august.commonadapter;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.ImageView;
    import android.widget.TextView;
    import java.util.List;
    /**
     * Created by August on 16/4/9.
     */
    public class GeneralParentAdapter<T> extends BaseAdapter {
        private List<T> mDatas;
        private Context mContext;
        private int layoutID;
        private ViewHolder holder;
        public GeneralParentAdapter(List<T> mDatas, Context mContext, int layoutID) {
            this.mDatas = mDatas;
            this.mContext = mContext;
            this.layoutID = layoutID;
        }
        @Override
        public int getCount() {
            return mDatas.size();
        }
        @Override
        public Object getItem(int position) {
            return mDatas.get(position);
        }
        @Override
        public long getItemId(int position) {
            return 0;
        }
    }
    

    嗯,这就是那堆让人讨厌的经常反反复复去写的代码

    核心方法getView

    下面是Adapter的getView方法了,这里就要使用到ViewHolder了

    @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            holder = ViewHolder.getHolder(mContext, convertView, layoutID, parent);
            
            TextView mTextView = holder.getView(R.id.mTextView);
            mTextView.setText(mDatas.get(position));
            return holder.getConverview();
        }
    

    然后我们发现,第一行和最后一行也是可以复用的,而且我们需要返回一个converView,那么我们就在ViewHolder添加一个方法吧

    public View getConvertview() {
            return this.mConvertview;
        }
    

    迷之封装

    继续,我们的Adapter就能用的,但是还不行,我们再把设置内容那里抽取出来,这才是每个Adapter真正的不同之处.现在我们把Adapter变成抽象类,并设置抽象方法setContent

      @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            holder = ViewHolder.getHolder(mContext, convertView, layoutID, parent);
            setContent(holder, mDatas, position);
            return holder.getConverview();
        }
        public abstract void setContent(ViewHolder holder, List<T> mDatas, int position);
    

    最后我们就可以使用了

    用例

    ItemBean.java

    package com.example.august.commonadapter;
    /**
     * Created by August on 16/4/9.
     */
    public class ItemBean {
        public int imgID;
        public String text;
        public ItemBean(int imgID, String text) {
            this.imgID = imgID;
            this.text = text;
        }
    }
    

    item_text.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal">
        <ImageView
            android:id="@+id/mImageView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <TextView
            android:id="@+id/mTextView"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:textSize="18sp" />
    </LinearLayout>
    

    调用代码

            mListView = (ListView) findViewById(R.id.mListView);
            List<ItemBean> mDatas = new ArrayList<ItemBean>();
            for (int i = 'A'; i < 'Z'; i++) {
                ItemBean itemBean = new ItemBean(R.drawable.pic, String.valueOf((char) i));
                mDatas.add(itemBean);
            }
            GeneralParentAdapter<ItemBean> mAdapter = new GeneralParentAdapter<ItemBean>(mDatas, MainActivity.this, R.layout.item_text) {
                @Override
                public void setContent(ViewHolder holder, List<ItemBean> mDatas, int postion) {
                    TextView mTextView = holder.getView(R.id.mTextView);
                    mTextView.setText("666");
                    ImageView mImageView = holder.getView(R.id.mImageView);
                    mImageView.setImageResource(R.drawable.pic);
                }
            };
            mListView.setAdapter(mAdapter);
    

    可以看到我们需要写的代码从一堆变成了短小精悍的几行,但还不够,我们还得上天呢 哈哈.我们再给ViewHolder设置一些通用的方法,无非是什么setText,setBitmap之类的,于是VIewHolder有了...

    接口的公布

      public void setText(int viewID, String text) {
            View childView = getView(viewID);
            if (childView instanceof TextView) {
                ((TextView) childView).setText(text);
            }
        }
        public void setBitmap(int viewID, Bitmap bitmap) {
            View childView = getView(viewID);
            if (childView instanceof ImageView) {
                ((ImageView) childView).setImageBitmap(bitmap);
            }
        }
    

    最后我们继续精简

            GeneralParentAdapter<ItemBean> mAdapter = new GeneralParentAdapter<ItemBean>(mDatas, MainActivity.this, R.layout.item_text) {
                @Override
                public void setContent(ViewHolder holder, List<ItemBean> mDatas, int postion) {
                    holder.setText(R.id.mTextView, mDatas.get(postion).text);
                    holder.setBitmap(R.id.mImageView, BitmapFactory.decodeResource(getResources(), R.drawable.pic));
                }
            };
    

    最后变成了两行代码,咱们就呵呵了...大家还可以根据自己需要去封装更多的方法.

    整体代码

    ViewHolder

    package com.example.august.commonadapter;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.util.SparseArray;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ImageView;
    import android.widget.TextView;
    /**
     * Created by August on 16/4/9.
     */
    public class ViewHolder {
        private SparseArray<View> mViews;
        private View mConvertview;
        public ViewHolder(View converview) {
            this.mConvertview = converview;
            mViews = new SparseArray<View>();
        }
        public static ViewHolder getHolder(Context context, View converview, int layoutID, ViewGroup parent) {
            ViewHolder holder = null;
            if (converview == null) {
                converview = LayoutInflater.from(context).inflate(layoutID, parent, false);
                holder = new ViewHolder(converview);
                converview.setTag(holder);
            } else {
                holder = (ViewHolder) converview.getTag();
            }
            return holder;
        }
        public <T extends View> T getView(int viewID) {
            T view = (T) mViews.get(viewID);
            if (view == null) {
                view = (T) mConvertview.findViewById(viewID);
                mViews.put(viewID, view);
            }
            return view;
        }
        public View getConverview() {
            return this.mConvertview;
        }
        public void setText(int viewID, String text) {
            View childView = getView(viewID);
            if (childView instanceof TextView) {
                ((TextView) childView).setText(text);
            }
        }
        public void setBitmap(int viewID, Bitmap bitmap) {
            View childView = getView(viewID);
            if (childView instanceof ImageView) {
                ((ImageView) childView).setImageBitmap(bitmap);
            }
        }
    }
    

    GeneralParentAdapter

    package com.example.august.commonadapter;
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.ImageView;
    import android.widget.TextView;
    import java.util.List;
    /**
     * Created by August on 16/4/9.
     */
    public abstract class GeneralParentAdapter<T> extends BaseAdapter {
        private List<T> mDatas;
        private Context mContext;
        private int layoutID;
        private ViewHolder holder;
        public GeneralParentAdapter(List<T> mDatas, Context mContext, int layoutID) {
            this.mDatas = mDatas;
            this.mContext = mContext;
            this.layoutID = layoutID;
        }
        @Override
        public int getCount() {
            return mDatas.size();
        }
        @Override
        public Object getItem(int position) {
            return mDatas.get(position);
        }
        @Override
        public long getItemId(int position) {
            return 0;
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            holder = ViewHolder.getHolder(mContext, convertView, layoutID, parent);
            setContent(holder, mDatas, position);
            return holder.getConverview();
        }
        public abstract void setContent(ViewHolder holder, List<T> mDatas, int position);
    }
    

    相关文章

      网友评论

        本文标题:Android打造一个通用的BaseAdapter

        本文链接:https://www.haomeiwen.com/subject/bzvowttx.html