編輯:關於Android編程
public class SimpleAdapter extends BaseAdapter {
public static class ViewHolder {
public TextView tvName;
}
private List studentList;
private LayoutInflater inflater;
public SimpleAdapter(Context context, List students) {
inflater = LayoutInflater.from(context);
this.studentList = students;
}
@Override
public int getCount() {
return studentList.size();
}
@Override
public Student getItem(int position) {
return studentList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
View view = convertView;
if (view == null) {
view = inflater.inflate(android.R.layout.simple_list_item_1, parent, false);
holder = new ViewHolder();
holder.tvName = (TextView) view.findViewById(android.R.id.text1);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
Student student = getItem(position);
holder.tvName.setText(student.naem);
return view;
}
}
Activity中調用
setListAdapter(new SimpleAdapter(getContext(),datas));
這段代碼應該不陌生,當繼承BaseAdapter,必須重寫getCount、getItem、getItemId、getView這4個方法,然後寫一個構造方法傳入實體對象。可以說你再寫一個BaseAdapter也是同樣的寫法,仔細的你應該會發現,只有構造方法實體對象與getView中方法體業務邏輯有差異嘛,那麼是不是可以把實體對象改寫成泛型,getView方法體業務邏輯抽象出來,在外實現呢?那是必須可以的,接下來我們一步一步改善這要命的重復代碼。
public class CygAdapter上面代碼已成功把實體對象改成了泛型,但是getView中的業務邏輯這時出現了上面代碼中的問題,無法取到name變量,難道給Student實體類加注解?對於一個Student類注解是行得通滴,加一個@name注解嘛,但是又來一個學校School類、班級Class類那豈不是加N個不同命名的注解?這樣一來加注解方案肯定就走不下去了。那麼我們可以嘗試把getView的業務邏輯抽象出來在外部實現,那現在就需要一個抽象方法了。extends BaseAdapter {//變化 public static class ViewHolder { public TextView tvName; } private List studentList;//變化 private LayoutInflater inflater; public CygAdapter(Context context, List students) { inflater = LayoutInflater.from(context); this.studentList = students; } @Override public int getCount() { return studentList.size(); } @Override public T getItem(int position) {//變化 return studentList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder; View view = convertView; if (view == null) { view = inflater.inflate(android.R.layout.simple_list_item_1, parent, false); holder = new ViewHolder(); holder.tvName = (TextView) view.findViewById(android.R.id.text1); view.setTag(holder); } else { holder = (ViewHolder) view.getTag(); } T student = getItem(position);//變化 holder.tvName.setText(student.naem);//這裡出問題咯,這個T泛型類根本就沒有name變量嘛,怎麼辦? return view; } }
我們再CygAdapter改造一下,新建一個抽象方法onBindData(ViewHolder viewHolder, final T item, final int position);
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
View view = convertView;
if (view == null) {
view = inflater.inflate(android.R.layout.simple_list_item_1, parent, false);
holder = new ViewHolder();
holder.tvName = (TextView) view.findViewById(android.R.id.text1);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
T student = getItem(position);
//holder.tvName.setText(student.naem);//這裡出問題咯,怎麼辦?
onBindData(holder,student,position);//把上面holder.tvName.setText(student.naem)抽象到外部實現
return view;
}
//新建抽象方法
public abstract void onBindData(ViewHolder viewHolder, final T item, final int position);
再來看在Activity中用法
setListAdapter(new com.mylhyl.cygadapter.sample.blog.CygAdapter(getContext(),datas) {
@Override
public void onBindData(ViewHolder viewHolder, Student item, int position) {
viewHolder.tvName.setText(item.naem);
}
});
換一個School對象試試
ArrayList datas = new ArrayList();
datas.add(new School("珠海北師大"));
datas.add(new School("長沙湖南大學"));
setListAdapter(new com.mylhyl.cygadapter.sample.blog.CygAdapter(getContext(), datas) {
@Override
public void onBindData(ViewHolder viewHolder, School item, int position) {
viewHolder.tvName.setText(item.address);
}
});
是不是爽YY了,不管換什麼實體對象照樣搞定你。Student與School二個實體類都分別只有一個屬性name、address,那麼現在需求上變化,在Student類中新增一個age年齡屬性,顯示在ListView上。這樣一來我們的layout就得新加一個TextView來用顯示age,我們就不新建了利用系統自帶的android.R.layout.simple_list_item_2,於是就可以開干了,重新構造List
ArrayList datas = new ArrayList();
datas.add(new Student(21,"張三"));
datas.add(new Student(22,"李四"));
setListAdapter(new com.mylhyl.cygadapter.sample.blog.CygAdapter(getContext(), datas) {
@Override
public void onBindData(ViewHolder viewHolder, Student item, int position) {
viewHolder.tvName.setText(item.naem);
viewHolder.tvAge.setText(String.valueOf(item.age));//尼瑪沒有ViewHolder中沒有tvAge呀
}
});
上面代碼ViewHolder中沒有tvAge呀,新建一個不就得了,這樣肯定是不行的,與剛才說的加注解方案一樣的道理,ViewHolder中的變量只會越來越多,怎麼辦呢?竟然問題出現在ViewHolder就得從他來下手,我們看getView中的那段ViewHolder相關的代碼
沒有加age之前
ViewHolder holder;
View view = convertView;
if (view == null) {
view = inflater.inflate(android.R.layout.simple_list_item_1, parent, false);//一個TextView
holder = new ViewHolder();
holder.tvName = (TextView) view.findViewById(android.R.id.text1);//名字
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
加age之後
ViewHolder holder;
View view = convertView;
if (view == null) {
view = inflater.inflate(android.R.layout.simple_list_item_2, parent, false);//二個TextView
holder = new ViewHolder();
holder.tvName = (TextView) view.findViewById(android.R.id.text1);//名字
holder.tvAge = (TextView) view.findViewById(android.R.id.text2);//年齡
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
上面代碼是不是看出點什麼呢?是不是除了inflate與findViewById部分不一樣,那是不是有點思路了?新建一個類抽出相同部分,寫成一個通用的ViewHolder,開干吧!
public final class CygViewHolder {
private Context mContext;
private View mItemView;
public static CygViewHolder get(Context context, int resource, View convertView, ViewGroup parent) {
if (convertView == null) {
View view = LayoutInflater.from(context).inflate(resource, parent, false);
return new CygViewHolder(context, view);
}
return (CygViewHolder) convertView.getTag();
}
private CygViewHolder(Context context, View itemView) {
mContext = context;
mItemView = itemView;
mItemView.setTag(this);
}
public View getItemView() {
return mItemView;
}
}
CygAdapter
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//沒有了一堆重復代碼
CygViewHolder viewHolder = CygViewHolder.get(context, resource, convertView, parent);
T student = getItem(position);
onBindData(viewHolder, student, position);
return viewHolder.getItemView();
}
//ViewHolder改為CygViewHolder
public abstract void onBindData(CygViewHolder viewHolder, final T item, final int position);
ListView綁定CygAdapter的時候出現問題了,無法查找控件
ArrayList datas = new ArrayList();
datas.add(new Student(21,"張三"));
datas.add(new Student(22,"李四"));
setListAdapter(new com.mylhyl.cygadapter.sample.blog.CygAdapter(getContext(), datas) {
@Override
public void onBindData(CygViewHolder viewHolder, Student item, int position) {
//查找TextView,還是沒有tvName\tvAge?又得如何處理,想個辦法
viewHolder.tvName = (TextView) view.findViewById(android.R.id.text1);
viewHolder.tvAge = (TextView) view.findViewById(android.R.id.text2);
//為TextView設置數據
viewHolder.tvName.setText(item.naem);
viewHolder.tvAge.setText(String.valueOf(item.age));
}
});
上面代碼onBindData綁定數據代碼段的問題如何處理呢?思路是這樣,既然CygViewHolder中已經有了每個Item的View,那麼我們可以在CygViewHolder寫個findViewById方法查找控件,並緩存在SparseArray
public final class CygViewHolder {
private Context mContext;
private SparseArray mViews;//變化
private View mItemView;
public static CygViewHolder get(Context context, int resource, View convertView,
ViewGroup parent) {
if (convertView == null) {
View view = LayoutInflater.from(context).inflate(resource, parent, false);
return new CygViewHolder(context, view);
}
return (CygViewHolder) convertView.getTag();
}
private CygViewHolder(Context context, View itemView) {
mContext = context;
mViews = new SparseArray<>();//變化
mItemView = itemView;
mItemView.setTag(this);
}
public T findViewById(int id) {//新增方法
View view = mViews.get(id);
if (view == null) {
view = mItemView.findViewById(id);
mViews.put(id, view);
}
return (T) view;
}
}
使用
ArrayList datas = new ArrayList();
datas.add(new Student(21, "張三"));
datas.add(new Student(22, "李四"));
setListAdapter(new com.mylhyl.cygadapter.sample.blog.CygAdapter
(getContext(), android.R.layout.simple_list_item_2, datas) {
@Override
public void onBindData(CygViewHolder viewHolder, Student item, int position) {
TextView tvName = viewHolder.findViewById(android.R.id.text1);
TextView tvAge = viewHolder.findViewById(android.R.id.text2);
tvName.setText(item.naem);
tvAge.setText(String.valueOf(item.age));
}
});
現在是不是簡單多了,adapter通用,只需使用時在onBindData中查到控件、給控件綁定數據,就這麼簡單。
內容比較多寫的啰嗦了點,但出發點是好的,請耐心閱讀,勿噴哦!!!
本庫地址:https://github.com/mylhyl/Android-CygAdapter
Android 組件樣式定制方法詳解
前言android中有很多現成的組件可以使用,但是android上面的程序很多時候用系統自帶的組件都不太合適,主要是樣式可能不是我們想要的。這個時候我們就需要定制一些樣式
android apk反編譯到java源碼的實現方法
Android由於其代碼是放在dalvik虛擬機上的托管代碼,所以能夠很容易的將其反編譯為我們可以識別的代碼。之前我寫過一篇文章反編譯Android的apk包到smali
小米手機助手怎麼刷機
這個世界就是這麼奇妙,明明手機賣的非常好,還要做手機助手,當然了我只當是給客戶的福利。VIVO除了vivo手機助手,小米也有小米手機助手。那麼小米手機助手可
JAVA基礎再回首(二十三)——操作基本數據類型的流、內存操作流、打印流、隨機訪問流、合並流、序列化流
有些日子沒寫博客了,當然這段時間也比較忙,大家見諒,好了,話不多說,開始學習吧。我們繼續學習IO流,還有幾個知識點沒有學。操作基本數據類型的流操作基本數據類型DataIn