天天看點

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="[email protected]" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >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="[email protected]" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >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="[email protected]" target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow"  target="_blank" rel="external nofollow" >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