高灵活低耦合Adapter快速开发攻略
Android开发中经常需要使用Adapter。
传统方法是自定义一个Adapter并继承AndroidSDK内的BaseAdapter,
这种方式代码量大,耦合度高,灵活性差(各种监听事件需要对View单独写,或者自定义一个比较统一的方法);
而ZBLibrary中的BaseViewAdapter不仅预处理了通用方法(getCount,getItem等) 以及 Item复用逻辑,
而且将对Item的处理代码单独写在一个BaseView(提供了大量常用方法)的子类,
所以使用继承BaseViewAdapter的新方式能大幅精简代码,并且带来高灵活性和低耦合度。
比如这个界面
传统方式实现的CommonAdapter代码如下
1 package com.example.quickadapter; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 import zuo.biao.library.ui.WebViewActivity; 7 import zuo.biao.library.util.ImageLoaderUtil; 8 import android.app.Activity; 9 import android.view.LayoutInflater; 10 import android.view.View; 11 import android.view.View.OnClickListener; 12 import android.view.ViewGroup; 13 import android.widget.BaseAdapter; 14 import android.widget.ImageView; 15 import android.widget.TextView; 16 17 public class CommonAdapter extends BaseAdapter { 18 19 private Activity context; 20 private List<User> list; 21 private LayoutInflater inflater; 22 public CommonAdapter(Activity context, List<User> list) { 23 this.context = context; 24 this.list = new ArrayList<>(list); 25 this.inflater = context.getLayoutInflater(); 26 } 27 28 @Override 29 public int getCount() { 30 return list.size(); 31 } 32 33 @Override 34 public User getItem(int position) { 35 return list.get(position); 36 } 37 38 @Override 39 public long getItemId(int position) { 40 return position; 41 } 42 43 public synchronized void refresh(List<User> list) { 44 if (list != null && list.size() > 0) { 45 this.list = new ArrayList<>(list); 46 } 47 notifyDataSetChanged(); 48 } 49 50 @Override 51 public View getView(final int position, View convertView, ViewGroup parent) { 52 ViewHolder holder = convertView == null ? null : (ViewHolder) convertView.getTag(); 53 if (holder == null) { 54 convertView = inflater.inflate(R.layout.user_item, parent, false); 55 holder = new ViewHolder(); 56 57 holder.ivUserItemHead = (ImageView) convertView.findViewById(R.id.ivUserItemHead); 58 holder.ivUserItemStar = (ImageView) convertView.findViewById(R.id.ivUserItemStar); 59 60 holder.tvUserItemSex = (TextView) convertView.findViewById(R.id.tvUserItemSex); 61 62 holder.tvUserItemName = (TextView) convertView.findViewById(R.id.tvUserItemName); 63 holder.tvUserItemId = (TextView) convertView.findViewById(R.id.tvUserItemId); 64 holder.tvUserItemNumber = (TextView) convertView.findViewById(R.id.tvUserItemNumber); 65 66 convertView.setTag(holder); 67 } 68 69 final User user = getItem(position); 70 71 ImageLoaderUtil.loadImage(holder.ivUserItemHead, user.getHead(), ImageLoaderUtil.TYPE_OVAL); 72 holder.ivUserItemStar.setImageResource(user.getStarred() ? R.drawable.star_light : R.drawable.star); 73 74 holder.tvUserItemSex.setBackgroundResource(user.getSex() == User.SEX_FEMAIL ? R.drawable.circle_pink : R.drawable.circle_blue); 75 holder.tvUserItemSex.setText(user.getSex() == User.SEX_FEMAIL ? "女" : "男"); 76 holder.tvUserItemSex.setTextColor(context.getResources().getColor(user.getSex() == User.SEX_FEMAIL ? R.color.pink : R.color.blue)); 77 78 holder.tvUserItemName.setText("" + user.getName()); 79 holder.tvUserItemId.setText("ID:" + user.getId()); 80 holder.tvUserItemNumber.setText("Phone:" + user.getPhone()); 81 82 holder.ivUserItemHead.setOnClickListener(new OnClickListener() { 83 84 @Override 85 public void onClick(View v) { 86 context.startActivity(WebViewActivity.createIntent(context, user.getName(), user.getHead())); 87 } 88 }); 89 90 holder.ivUserItemStar.setOnClickListener(new OnClickListener() { 91 92 @Override 93 public void onClick(View v) { 94 user.setStarred(! user.getStarred()); 95 list.set(position, user); 96 refresh(null); 97 } 98 }); 99 100 holder.tvUserItemSex.setOnClickListener(new OnClickListener() { 101 102 @Override 103 public void onClick(View v) { 104 user.setSex(user.getSex() == User.SEX_FEMAIL ? User.SEX_MAIL : User.SEX_FEMAIL); 105 list.set(position, user); 106 refresh(null); 107 } 108 }); 109 110 return convertView; 111 } 112 113 class ViewHolder { 114 public ImageView ivUserItemHead; 115 public ImageView ivUserItemStar; 116 117 public TextView tvUserItemSex; 118 119 public TextView tvUserItemName; 120 public TextView tvUserItemId; 121 public TextView tvUserItemNumber; 122 } 123 }
继承BaseViewAdapter的新方式实现的QuickAdapter代码如下
1 package com.example.quickadapter; 2 3 import java.util.List; 4 5 import zuo.biao.library.base.BaseView; 6 import zuo.biao.library.base.BaseViewAdapter; 7 import zuo.biao.library.ui.WebViewActivity; 8 import zuo.biao.library.util.ImageLoaderUtil; 9 import zuo.biao.library.util.StringUtil; 10 import android.annotation.SuppressLint; 11 import android.app.Activity; 12 import android.content.res.Resources; 13 import android.view.LayoutInflater; 14 import android.view.View; 15 import android.view.View.OnClickListener; 16 import android.view.ViewGroup; 17 import android.widget.ImageView; 18 import android.widget.TextView; 19 20 import com.example.quickadapter.QuickAdapter.UserView; 21 22 public class QuickAdapter extends BaseViewAdapter<User, UserView> { 23 24 public QuickAdapter(Activity context, List<User> list) { 25 super(context, list); 26 } 27 28 @Override 29 public UserView createView(int position, View convertView, ViewGroup parent) { 30 return new UserView(context, resources); 31 } 32 33 public class UserView extends BaseView<User> implements OnClickListener { 34 public UserView(Activity context, Resources resources) { 35 super(context, resources); 36 } 37 38 public ImageView ivUserViewHead; 39 public ImageView ivUserViewStar; 40 41 public TextView tvUserViewSex; 42 43 public TextView tvUserViewName; 44 public TextView tvUserViewId; 45 public TextView tvUserViewNumber; 46 @SuppressLint("InflateParams") 47 @Override 48 public View createView(LayoutInflater inflater) { 49 convertView = inflater.inflate(R.layout.user_view, null); 50 51 ivUserViewHead = findViewById(R.id.ivUserViewHead, this); 52 ivUserViewStar = findViewById(R.id.ivUserViewStar, this); 53 54 tvUserViewSex = findViewById(R.id.tvUserViewSex, this); 55 56 tvUserViewName = findViewById(R.id.tvUserViewName); 57 tvUserViewId = findViewById(R.id.tvUserViewId); 58 tvUserViewNumber = findViewById(R.id.tvUserViewNumber); 59 60 return convertView; 61 } 62 63 @Override 64 public void setView(User data){ 65 if (data == null) { 66 return; 67 } 68 this.data = data; 69 70 ImageLoaderUtil.loadImage(ivUserViewHead, data.getHead(), ImageLoaderUtil.TYPE_OVAL); 71 ivUserViewStar.setImageResource(data.getStarred() ? R.drawable.star_light : R.drawable.star); 72 73 tvUserViewSex.setBackgroundResource(data.getSex() == User.SEX_FEMAIL ? R.drawable.circle_pink : R.drawable.circle_blue); 74 tvUserViewSex.setText(data.getSex() == User.SEX_FEMAIL ? "女" : "男"); 75 tvUserViewSex.setTextColor(getColor(data.getSex() == User.SEX_FEMAIL ? R.color.pink : R.color.blue)); 76 77 tvUserViewName.setText(StringUtil.getTrimedString(data.getName())); 78 tvUserViewId.setText("ID:" + data.getId()); 79 tvUserViewNumber.setText("Phone:" + StringUtil.getNoBlankString(data.getPhone())); 80 } 81 82 @Override 83 public void onClick(View v) { 84 if (data == null) { 85 return; 86 } 87 switch (v.getId()) { 88 case R.id.ivUserViewHead: 89 toActivity(WebViewActivity.createIntent(context, data.getName(), data.getHead())); 90 break; 91 case R.id.ivUserViewStar: 92 data.setStarred(! data.getStarred()); 93 setView(data); 94 break; 95 case R.id.tvUserViewSex: 96 data.setSex(data.getSex() == User.SEX_FEMAIL ? User.SEX_MAIL : User.SEX_FEMAIL); 97 setView(data); 98 break; 99 default: 100 break; 101 } 102 } 103 } 104 }
看下ZBLibrary中的BaseView,里面有大量常用的 且 AndroidSDK内的BaseAdapter没有提供的 方法。
package zuo.biao.library.base; import zuo.biao.library.util.CommonUtil; import zuo.biao.library.util.Log; import android.app.Activity; import android.content.Intent; import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.view.View.OnTouchListener; /**基础自定义View * @author Lemon * @param <T> 数据模型(model/JavaBean)类 * @see #onDestroy * @use extends BaseView<T>, 具体参考.DemoView */ public abstract class BaseView<T> { private static final String TAG = "BaseView"; /** * 传入的Activity,可在子类直接使用 */ protected Activity context; protected Resources resources; public BaseView(Activity context, Resources resources) { this.context = context; this.resources = resources == null ? context.getResources() : resources; } /**数据改变回调接口 * (Object) getData() - 改变的数据 */ public interface OnDataChangedListener { void onDataChanged(); } public OnDataChangedListener onDataChangedListener;//数据改变回调监听类的实例 /**设置数据改变事件监听类 * @param l */ public void setOnDataChangedListener(OnDataChangedListener l) { onDataChangedListener = l; } public OnTouchListener onTouchListener;//接触View回调监听类的实例 /**设置接触View事件监听类 * @param l */ public void setOnTouchListener(OnTouchListener l) { onTouchListener = l; } public OnClickListener onClickListener;//点击View回调监听类的实例 /**设置点击View事件监听类 * @param l */ public void setOnClickListener(OnClickListener l) { onClickListener = l; } public OnLongClickListener onLongClickListener;//长按View回调监听类的实例 /**设置长按View事件监听类 * @param l */ public void setOnLongClickListener(OnLongClickListener l) { onLongClickListener = l; } /** * 子类整个视图,可在子类直接使用 * @must createView方法内对其赋值且不能为null */ protected View convertView = null; /**通过id查找并获取控件,使用时不需要强转 * @param id * @return */ @SuppressWarnings("unchecked") public <V extends View> V findViewById(int id) { return (V) convertView.findViewById(id); } /**通过id查找并获取控件,并setOnClickListener * @param id * @param l * @return */ public <V extends View> V findViewById(int id, OnClickListener l) { V v = findViewById(id); v.setOnClickListener(l); return v; } /**创建一个新的View * @return */ public abstract View createView(@NonNull LayoutInflater inflater); /**获取convertView的宽度 * @warn 只能在createView后使用 * @return */ public int getWidth() { return convertView.getWidth(); } /**获取convertView的高度 * @warn 只能在createView后使用 * @return */ public int getHeight() { return convertView.getHeight(); } /** * data在列表中的位置 * @must 只使用setView(int position, T data)方法来设置position,保证position与data对应正确 */ protected int position = 0; /**获取data在列表中的位置 */ public int getPosition() { return position; } protected T data = null; /**获取数据 * @return */ public T getData() { return data; } /**设置并显示内容 * @warn 只能在createView后使用 * @param position - data在列表中的位置 * @param data - 传入的数据 */ public void setView(int position, T data) { this.position = position; setView(data); } /**设置并显示内容 * @warn 只能在createView后使用 * @param data - 传入的数据 */ public abstract void setView(T data); /**获取可见性 * @warn 只能在createView后使用 * @return 可见性 (View.VISIBLE, View.GONE, View.INVISIBLE); */ public int getVisibility() { return convertView.getVisibility(); } /**设置可见性 * @warn 只能在createView后使用 * @param visibility - 可见性 (View.VISIBLE, View.GONE, View.INVISIBLE); */ public void setVisibility(int visibility) { convertView.setVisibility(visibility); } /**设置背景 * @warn 只能在createView后使用 * @param resId */ public void setBackground(int resId) { if (resId > 0 && convertView != null) { try { convertView.setBackgroundResource(resId); } catch (Exception e) { Log.e(TAG, "setBackground try { convertView.setBackgroundResource(resId);" + " \n >> } catch (Exception e) { \n" + e.getMessage()); } } } //resources方法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< public String getString(int id) { return resources.getString(id); } public int getColor(int id) { return resources.getColor(id); } public Drawable getDrawable(int id) { return resources.getDrawable(id); } public float getDimension(int id) { return resources.getDimension(id); } //resources方法>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> //show short toast 方法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< /**快捷显示short toast方法,需要long toast就用 Toast.makeText(string, Toast.LENGTH_LONG).show(); ---不常用所以这个类里不写 * @param stringResId */ public void showShortToast(int stringResId) { CommonUtil.showShortToast(context, stringResId); } /**快捷显示short toast方法,需要long toast就用 Toast.makeText(string, Toast.LENGTH_LONG).show(); ---不常用所以这个类里不写 * @param string */ public void showShortToast(String string) { CommonUtil.showShortToast(context, string); } //show short toast 方法>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> //启动新Activity方法<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< /**打开新的Activity,向左滑入效果 * @param intent */ public void toActivity(final Intent intent) { CommonUtil.toActivity(context, intent); } /**打开新的Activity * @param intent * @param showAnimation */ public void toActivity(final Intent intent, final boolean showAnimation) { CommonUtil.toActivity(context, intent, showAnimation); } /**打开新的Activity,向左滑入效果 * @param intent * @param requestCode */ public void toActivity(final Intent intent, final int requestCode) { CommonUtil.toActivity(context, intent, requestCode); } /**打开新的Activity * @param intent * @param requestCode * @param showAnimation */ public void toActivity(final Intent intent, final int requestCode, final boolean showAnimation) { CommonUtil.toActivity(context, intent, requestCode, showAnimation); } //启动新Activity方法>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> /**销毁并回收内存,建议在对应的View占用大量内存时使用 * @warn 只能在UI线程中调用 */ public void onDestroy() { if (convertView != null) { try { convertView.destroyDrawingCache(); } catch (Exception e) { Log.w(TAG, "onDestroy try { convertView.destroyDrawingCache();" + " >> } catch (Exception e) {\n" + e.getMessage()); } convertView = null; } onDataChangedListener = null; onTouchListener = null; onClickListener = null; onLongClickListener = null; data = null; position = 0; context = null; } }
本示例工程QuickAdapter
下载地址
https://files.cnblogs.com/files/tommylemon/QuickAdapter.zip
下载试用
用到的开源库ZBLibrary(欢迎Star,欢迎Fork)
下载地址
https://github.com/TommyLemon/Android-ZBLibrary
下载试用