在Android开发中一个项目需要在很多地方使用的ListView。既然使用了ListView则不可避免的使用了Adapter,重复写逻辑几乎相同的Adapter也是一件枯燥的事,下面来研究如何复用Adapter.
使用了ListView的两个地方(模拟代码):
一.//第一个ListView
listView.setAdapter(new MyAdapter());
class MyAdapter extends BaseAdapter{
//arrayList是设置给ListView数据的集合
@Override
public int getCount() {
return arrayList.size();
}
@Override
public Object getItem(int i) {
return arrayList.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder =null;
if(view == null){
view = View.inflate(ThemeFragment.this.getActivity(), R.layout.theme_adapt_item,null);
viewHolder = new ViewHolder();
viewHolder.icon = (ImageView) view.findViewById(R.id.theme_iv);
viewHolder.textView = (TextView) view.findViewById(R.id.theme_text);
view.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) view.getTag();
}
//给ViewHolder设置值,即给ListView的各个组件设置值
BitmapHelper.getBitmapUtils().display(viewHolder.icon, GlobalUrl.ICON_URL+theme.themeInfos.get(i).url);
viewHolder.textView.setText(theme.themeInfos.get(i).des);
return view;
}
}
//为了优化ListView不可避免的使用了ViewHolder来复用
static class ViewHolder{
ImageView icon;
TextView textView;
}
二.//第二个ListView
listView.setAdapter(new MyAdapter());
class MyAdapter extends BaseAdapter{
//arrayList是设置给ListView数据的集合
@Override
public int getCount() {
return arrayList.size();
}
@Override
public Object getItem(int i) {
return arrayList.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder =null;
if(view == null){
view = View.inflate(HomeFragment.this.getActivity(), R.layout.home_adapt_item, null);
viewHolder = new ViewHolder();
viewHolder.item_icon = (ImageView) view.findViewById(R.id.item_icon);
viewHolder.app_name = (TextView) view.findViewById(R.id.item_title);
viewHolder.app_size = (TextView) view.findViewById(R.id.item_size);
viewHolder.app_introduce = (TextView) view.findViewById(R.id.item_bottom);
view.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) view.getTag();
}
//给ViewHolder设置值,即给ListView的各个组件设置值
BitmapHelper.getBitmapUtils().display(this.item_icon, GlobalUrl.ICON_URL + detailAppInfos.iconUrl);
this.app_name.setText(detailAppInfos.name);
this.app_size.setText(detailAppInfos.size);
this.app_introduce.setText(detailAppInfos.des);
return view;
}
}
//为了优化ListView不可避免的使用了ViewHolder来复用
static class ViewHolder{
ImageView item_icon;
TextView app_name;
TextView app_size;
TextView app_introduce;
}
如上两段代码是在开发过程中经常使用到的,现在对Adapter进行抽取封装:
1.首先Adapter的前三个方法:getCount(),getItem(),getItemId()是完全一样的,通过一个ArrayList来完成。我们抽取的Adapter让子类注入一个ArrayList进来:
public class DefaultAdapter<T> extends BaseAdapter {
private List<T> listData;
public DefaultAdapter(List<T> list){
this.listData = list;
}
@Override
public int getCount() {
return listData.size();
}
@Override
public Object getItem(int i) {
return listData.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
return null;
}
}
2.此时Adapter中的getView()显示的很臃肿,为了getView()方法的简介,将getView()方法与为了复用的ViewHolder进行进一步修改(针对第二个ListView):
Adapter:
class MyAdapter extends DefaultAdapter<HomeInfos.DetailAppInfos>{
public MyAdapter(List<HomeInfos.DetailAppInfos> list) {
super(list);
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder viewHolder = null;
if(view==null){
//所有的初始化view的方法全部放在ViewHolder的构造方法中
viewHolder = new ViewHolder();
}else{
viewHolder = (ViewHolder) view.getTag();
}
//设置数据的方法也放在viewHolder中,而设置的具体数据(集合中的数据)注入进去
viewHolder.setDetailInfos(homeInfos.list.get(i));
return viewHolder.getView();
}
}
ViewHolder:
static class ViewHolder{
ImageView item_icon;
TextView app_name;
TextView app_size;
TextView app_introduce;
//显示的每个条目的View
private View view;
private BitmapUtils bitmapUtils;
//集合中的数据,设置给每个ListView条目的
private HomeInfos.DetailAppInfos detailAppInfos;
//注入的方法
public void setDetailInfos(HomeInfos.DetailAppInfos detailAppInfos) {
this.detailAppInfos = detailAppInfos;
//注入成功后,刷新view。刷新view即是把集合中的数据设置给viewHolder
refreshView();
}
public ViewHolder(){
bitmapUtils = BitmapHelper.getBitmapUtils();
view = View.inflate(UiUtil.getContext(), R.layout.home_adapt_item, null);
this.item_icon = (ImageView) view.findViewById(R.id.item_icon);
this.app_name = (TextView) view.findViewById(R.id.item_title);
this.app_size = (TextView) view.findViewById(R.id.item_size);
this.app_introduce = (TextView) view.findViewById(R.id.item_bottom);
view.setTag(this);
}
public View getView() {
return view;
}
//集合中的数据设置给viewHolder
public void refreshView(){
BitmapHelper.getBitmapUtils().display(this.item_icon, GlobalUrl.ICON_URL + detailAppInfos.iconUrl);
this.app_name.setText(detailAppInfos.name);
this.item_rating.setRating((float) detailAppInfos.stars);
this.app_size.setText(detailAppInfos.size);
this.app_introduce.setText(detailAppInfos.des);
}
}
3.将两个ListView都做如上操作之后会发现,getView变得极其相似了,那么我们可以把它提取到分类中:
此时就会发现一个问题,每个ListView的ViewHolder都不一样,所以我们把ViewHolder与进一部的进行抽象(针对第二个ListView):
BaseViewHolder:
public abstract class BaseViewHolder<T> {
private View view;
private BitmapUtils bitmapUtils;
private T detailInfos;
public void setDetailInfos(T detailInfos) {
this.detailInfos = detailInfos;
refreshView(detailInfos);
}
public BaseViewHolder(){
bitmapUtils = BitmapHelper.getBitmapUtils();
view = initView();
view.setTag(this);
}
public abstract View initView();
public View getView() {
return view;
}
public abstract void refreshView(T detailInfos);
}
经过抽取之后:每个ViewHolder只需要实现两个抽象方法
static class ViewHolder extends BaseViewHolder<HomeInfos.DetailAppInfos>{
ImageView item_icon;
TextView app_name;
RatingBar item_rating;
TextView app_size;
TextView app_introduce;
@Override
public View initView() {
View view = View.inflate(UiUtil.getContext(), R.layout.home_adapt_item, null);
this.item_icon = (ImageView) view.findViewById(R.id.item_icon);
this.app_name = (TextView) view.findViewById(R.id.item_title);
this.item_rating = (RatingBar) view.findViewById(R.id.item_rating);
this.app_size = (TextView) view.findViewById(R.id.item_size);
this.app_introduce = (TextView) view.findViewById(R.id.item_bottom);
return view;
}
@Override
public void refreshView(HomeInfos.DetailAppInfos detailAppInfos){
BitmapHelper.getBitmapUtils().display(this.item_icon, GlobalUrl.ICON_URL + detailAppInfos.iconUrl);
this.app_name.setText(detailAppInfos.name);
this.item_rating.setRating((float) detailAppInfos.stars);
this.app_size.setText(detailAppInfos.size);
this.app_introduce.setText(detailAppInfos.des);
}
}
4.此时,把getView()提取到抽象中:
对于每个ViewHolder也有了BaseViewHolder,但在getView()中生成具体的ViewHodler时不知道生成哪一个,所以可以定义一个获取子类ViewHolder的抽象方法,让子类返回一个自身的ViewHolder的实现(这儿类似与DAO设计模式中BaseServiceImpl声明一个抽象方法,让子类返回自身Dao的实现因为BaseServiceImpl不知道使用哪个Dao来完成,只能丢给子类来处理).
最终的代码(针对第二个ListView):
class MyAdapter extends DefaultAdapter<HomeInfos.DetailAppInfos>{
public MyAdapter(List<HomeInfos.DetailAppInfos> list) {
super(list);
}
@Override
protected BaseViewHolder getViewHolder() {
return new ViewHolder();
}
}
static class ViewHolder extends BaseViewHolder<HomeInfos.DetailAppInfos>{
ImageView item_icon;
TextView app_name;
TextView app_size;
TextView app_introduce;
@Override
public View initView() {
View view = View.inflate(UiUtil.getContext(), R.layout.home_adapt_item, null);
this.item_icon = (ImageView) view.findViewById(R.id.item_icon);
this.app_name = (TextView) view.findViewById(R.id.item_title);
this.app_size = (TextView) view.findViewById(R.id.item_size);
this.app_introduce = (TextView) view.findViewById(R.id.item_bottom);
return view;
}
@Override
public void refreshView(HomeInfos.DetailAppInfos detailAppInfos){
BitmapHelper.getBitmapUtils().display(this.item_icon, GlobalUrl.ICON_URL + detailAppInfos.iconUrl);
this.app_name.setText(detailAppInfos.name);
this.app_size.setText(detailAppInfos.size);
this.app_introduce.setText(detailAppInfos.des);
}
}
抽象的两个类Adapter和ViewHolder:
public abstract class DefaultAdapter<T> extends BaseAdapter {
private List<T> listData;
public DefaultAdapter(List<T> list){
this.listData = list;
}
@Override
public int getCount() {
return listData.size();
}
@Override
public Object getItem(int i) {
return listData.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
BaseViewHolder viewHolder =null;
if(view == null){
viewHolder = getViewHolder();
}else{
viewHolder = (BaseViewHolder) view.getTag();
}
viewHolder.setDetailInfos(listData.get(i));
return viewHolder.getView();
}
protected abstract BaseViewHolder getViewHolder();
}
public abstract class BaseViewHolder<T> {
private View view;
private BitmapUtils bitmapUtils;
private T detailInfos;
public void setDetailInfos(T detailInfos) {
this.detailInfos = detailInfos;
refreshView(detailInfos);
}
public BaseViewHolder(){
bitmapUtils = BitmapHelper.getBitmapUtils();
view = initView();
view.setTag(this);
}
public abstract View initView();
public View getView() {
return view;
}
public abstract void refreshView(T detailInfos);
}
这样就完成了ListView设置Adapter的抽象,以后需要使用Adapter的地方直接让Adapter继承DefaultAdapter。让ViewHolder实现BaseViewHolder,然后分别实现父类定义的抽象方法(Adapter实现返回自己ViewHolder的方法,ViewHolder实现生成每个条目的View方法和给这个View设置数据的方法)即可。