Android万能适配器CommonAdapter的源码分析

1.ViewFinder的实现

package com.mycollege.util;

import java.lang.ref.WeakReference;

import android.content.Context;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

/**
 * @{# ViewFinder.java Create on 2015-7-17 下午7:36:43
 * 		
 *     class desc:  view finder, 方便查找View。用户需要在使用时调用initContentView,
 * 					将Context和布局id传进来,然后使用findViewById来获取需要的view
 * 					,findViewById为泛型方法,返回的view则直接是你接收的类型,而不需要进行强制类型转换.比如,
 * 					以前我们在Activity中找一个TextView一般是这样 : TextView textView =
 * 					(TextView)findViewById(viewId); 如果页面中的控件比较多,就会有很多的类型转换,而使用ViewFinder则免去了类型转换,
 * 					示例如下 : TextView textView = ViewFinder.findViewById(viewId);
 * 
 *     <p>
 *     Copyright: Copyright(c) 2015
 *     </p>
 * @Version 1.0
 * Tel 15211164134 
 * Name 潘传爱
 * @Author <a href="15211164134@163.com">Hyca</a>
 * 
 */
public final class ViewFinder {

    /**
     * 
     */
    public static boolean DEBUG = false;

    /**
     * 每项的View的sub view Map
     */
    private static SparseArray<WeakReference<View>> mViewMap = new SparseArray<WeakReference<View>>();
    /**
     * Root View的弱引用,
     * 不会阻止View对象被释放。如果该mRootView没有被外部引用,那么在重新设置了rootView之后老的rootview会被释放.
     */
    private static WeakReference<View> mRootView;

    /**
     * 设置Content View
     * 
     * @param contentView 页面的Content View
     */
    public static void initContentView(View contentView) {

        if (contentView == null) {
            throw new RuntimeException(
                    "ViewFinder init failed, mContentView == null.");
        }

        //
        mRootView = new WeakReference<View>(contentView);
        // 每次清除缓存的view id
        mViewMap.clear();

    }

    /**
     * 初始化ViewFinder, 实际上是获取到该页面的ContentView.
     * 
     * @param context
     * @param layoutId
     */
    public static void initContentView(Context context, int layoutId) {
        initContentView(context, null, layoutId);
    }

    /**
     * @param context 上下文环境那个
     * @param parent 父组件 ( ViewGroup )
     * @param layoutId 布局id
     */
    public static void initContentView(Context context, ViewGroup parent, int layoutId) {
        if (context == null || layoutId <= 0) {
            throw new RuntimeException(
                    "initContentView invalid params, context == null || layoutId == -1.");
        }
        // inflate the root view
        View rootView = LayoutInflater.from(context).inflate(layoutId, parent, false);
        //
        initContentView(rootView);
    }

    /**
     * 返回顶级视图
     * 
     * @return
     */
    public static View getContentView() {
        return mRootView.get();
    }

    /**
     * @param viewId
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T extends View> T findViewById(int viewId) {

        // 先从view map中查找,如果有的缓存的话直接使用,否则再从mContentView中找
        View targetView = null;
        // get from weak reference
        WeakReference<View> viewWrf = mViewMap.get(viewId);
        if (viewWrf != null) {
            targetView = viewWrf.get();
        }

        if (targetView == null && mRootView != null && mRootView.get() != null) {
            targetView = mRootView.get().findViewById(viewId);
            mViewMap.put(viewId, new WeakReference<View>(targetView));
        }

        Log.d("", "### find view = " + targetView);
        return targetView == null ? null : (T) targetView;
    }

    @SuppressWarnings("unchecked")
    public static <T extends View> T findViewById(View rootView, int viewId) {

        // 先从view map中查找,如果有的缓存的话直接使用,否则再从mContentView中找
        View targetView = null;
        // get from weak reference
        if (rootView != null) {
            targetView = rootView.findViewById(viewId);
        }
        Log.d("", "### find view = " + targetView);
        return targetView == null ? null : (T) targetView;
    }

    /**
     * 清理Views
     */
    public static void clear() {
        if (mRootView != null) {
            mRootView.clear();
            mRootView = null;
        }

        if (mViewMap != null) {
            mViewMap.clear();
            mViewMap = null;
        }
    }
}

2.CommonViewHolder的实现

package com.mycollege.util;


import android.content.Context;
import android.graphics.Bitmap;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;

/**
 * @{# CommonViewHolder.java Create on 2015-7-17 下午7:35:59
 * 		
 *     class desc: 这是一个通用的ViewHolder, 将会装载AbsListView子类的item View, 并且将item
 * 				   view中的子视图进行缓存和索引,使得用户能够方便的获取这些子view, 减少了代码重复。
 *     <p>
 *     Copyright: Copyright(c) 2015
 *     </p>
 * @Version 1.0
 * Tel 15211164134 
 * Name 潘传爱
 * @Author <a href="15211164134@163.com">Hyca</a>
 * 
 */
public class CommonViewHolder {
    /**
     * 
     */
    private View mContentView;

    /**
     * 构造函数
     * 
     * @param context Context
     * @param layoutId ListView、GridView或者其他AbsListVew子类的 Item View的资源布局id
     */
    protected CommonViewHolder(Context context, ViewGroup parent, int layoutId) {
        mContentView = LayoutInflater.from(context).inflate(layoutId, parent, false);
        mContentView.setTag(this);
    }

    /**
     * 获取CommonViewHolder,当convertView为空的时候从布局xml装载item view,
     * 并且将该CommonViewHolder设置为convertView的tag, 便于复用convertView.
     * 
     * @param context Context
     * @param convertView Item view
     * @param layoutId 布局资源id, 例如R.layout.my_listview_item.
     * @return 通用的CommonViewHolder实例
     */
    public static CommonViewHolder getViewHolder(Context context, View convertView,
            ViewGroup parent, int layoutId) {

        context = (context == null && parent != null) ? parent.getContext() : context;
        CommonViewHolder viewHolder = null;
        if (convertView == null) {
            viewHolder = new CommonViewHolder(context, parent, layoutId);
        } else {
            viewHolder = (CommonViewHolder) convertView.getTag();
        }

        // 将当前item view设置为ViewFinder要查找的root view, 这一步不能搞错,否则查找不到对象的view
        // ViewFinder.initContentView(viewHolder.getContentView());

        return viewHolder;
    }

    /**
     * @return 当前项的convertView, 在构造函数中装载
     */
    public View getContentView() {
        return mContentView;
    }

    /**
     * 为id为textViewId的TextView设置文本内容
     * 
     * @param textViewId 视图id
     * @param text 要设置的文本内容
     */
    public void setTextForTextView(int textViewId, CharSequence text) {
        TextView textView = ViewFinder.findViewById(mContentView, textViewId);
        if (textView != null) {
            textView.setText(text);
        }
    }

    /**
     * 为ImageView设置图片
     * 
     * @param imageViewId ImageView的id, 例如R.id.my_imageview
     * @param drawableId Drawable图片的id, 例如R.drawable.my_photo
     */
    public void setImageForView(int imageViewId, int drawableId) {
        ImageView imageView = ViewFinder.findViewById(mContentView, imageViewId);
        if (imageView != null) {
            imageView.setImageResource(drawableId);
        }
    }

    /**
     * 为ImageView设置图片
     * 
     * @param imageViewId ImageView的id, 例如R.id.my_imageview
     * @param bmp Bitmap图片
     */
    public void setImageForView(int imageViewId, Bitmap bmp) {
        ImageView imageView = ViewFinder.findViewById(mContentView, imageViewId);
        if (imageView != null) {
            imageView.setImageBitmap(bmp);
        }
    }

    /**
     * 为CheckBox设置是否选中
     * 
     * @param checkViewId CheckBox的id
     * @param isCheck 是否选中
     */
    public void setCheckForCheckBox(int checkViewId, boolean isCheck) {
        CheckBox checkBox = ViewFinder.findViewById(mContentView, checkViewId);
        if (checkBox != null) {
            checkBox.setChecked(isCheck);
        }
    }

    /**
     * @param viewId
     * @param visibility
     */
    public void setVisibility(int viewId, int visibility) {
        View view = ViewFinder.findViewById(mContentView, viewId);
        if (view != null) {
            view.setVisibility(visibility);
        }
    }

    /**
     * @param viewId
     * @param listener
     */
    public void setOnClickListener(int viewId, OnClickListener listener) {
        View view = ViewFinder.findViewById(mContentView, viewId);
        if (view != null) {
            view.setOnClickListener(listener);
        }
    }

    /**
     * @param viewId
     * @param listener
     */
    public void setOnTouchListener(int viewId, OnTouchListener listener) {
        View view = ViewFinder.findViewById(mContentView, viewId);
        if (view != null) {
            view.setOnTouchListener(listener);
        }
    }
}

3.CommonAdapter实现

package com.mycollege.adapter;

import java.util.List;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

import com.mycollege.util.CommonViewHolder;

/**
 * @{# CommonAdapter.java Create on 2015-7-17 下午7:34:54
 * 		
 *     class desc:  这是一个通用、抽象的适配器类,覆写了BaseAdapter的getCount, getItem, getItemId,
 * 					getView方法,在getView方法中通过
 * 					通用的CommonViewHolder来对convertView的进行处理,并且缓存convertView中的其他View元素
 *					 ,降低了ListView、GridView 等组件的Adapter和ViewHolder的代码量.
 *					 用户只需要在fillItemData函数中将第position位置里的数据填充到listview或者gridview的第position的view中即可
 *					 ,具体使用实例参考文档.
 *     <p>
 *     Copyright: Copyright(c) 2015
 *     </p>
 * @Version 1.0
 * Tel 15211164134 
 * Name 潘传爱
 * @Author <a href="15211164134@163.com">Hyca</a>
 * 
 */
public abstract class CommonAdapter<T> extends BaseAdapter {

    /**
     * Context
     */
    Context mContext;
    /**
     * 要展示的数据列表
     */
    List<T> mData;
    /**
     * 每一项的布局id,例如R.layout.my_listview_item.
     */
    private int mItemLayoutId = -1;

    /**
     * @param context Context
     * @param itemLayoutResId
     *            每一项(适用于listview、gridview等AbsListView子类)的布局资源id,例如R.layout.
     *            my_listview_item.
     * @param dataSource 数据源
     */
    public CommonAdapter(Context context, int itemLayoutResId, List<T> dataSource) {
        checkParams(context, itemLayoutResId, dataSource);
        mContext = context;
        mItemLayoutId = itemLayoutResId;
        mData = dataSource;
    }

    /**
     * 检查参数的有效性
     * 
     * @param context
     * @param itemLayoutResId
     * @param dataSource
     */
    private void checkParams(Context context, int itemLayoutResId, List<T> dataSource) {
        if (context == null || itemLayoutResId < 0 || dataSource == null) {
            throw new RuntimeException(
                    "context == null || itemLayoutResId < 0 || dataSource == null, please check your params");
        }
    }

    /**
     * 返回数据的总数
     */
    @Override
    public int getCount() {
        return mData.size();
    }

    /**
     * 返回position位置的数据
     */
    @Override
    public T getItem(int position) {
        return mData.get(position);
    }

    /**
     * item id, 返回position
     */
    @Override
    public long getItemId(int position) {
        return position;
    }

    /**
     * 返回position位置的view, 即listview、gridview的第postion个view
     */
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // 获取ViewHolder
        CommonViewHolder viewHolder = CommonViewHolder.getViewHolder(mContext, convertView, parent,
                mItemLayoutId);
        // 填充数据
        fillItemData(viewHolder, position, getItem(position));
        // 返回convertview
        return viewHolder.getContentView();
    }

    /**
     * 用户必须覆写该方法来讲数据填充到视图中
     * 
     * @param viewHolder 通用的ViewHolder, 里面会装载listview,
     *            gridview等组件的每一项的视图,并且缓存其子view
     * @param item 数据源的第position项数据
     */
    protected abstract void fillItemData(CommonViewHolder viewHolder, int position, T item);

}

4.
万能适配器的使用代码(这里的参数你可以看一下源码)

	CommonAdapter<AsAccountSecureEntity> adapter = new CommonAdapter<AsAccountSecureEntity>(this, R.layout.item_asaccountsecure, getListAsAccountSecureEntity()) {

		@Override
		protected void fillItemData(CommonViewHolder viewHolder, int position,
				AsAccountSecureEntity item) {
			viewHolder.setTextForTextView(R.id.tv_accountsecure, item.name);
			viewHolder.setTextForTextView(R.id.tv_accountsecurevalue, item.value);
			//viewHolder.setImageForView(R.id.iv_accountsecure, item.drawableLeft);
			//viewHolder.setImageForView(R.id.iv_accountsecureclick, item.drawableRight);
		}
	};

源码下载地址:http://download.csdn.net/detail/pcaxb/9037975


    原文作者:Android源码分析
    原文地址: https://blog.csdn.net/pcaxb/article/details/47905091
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞