Android中的Adapter(适配器)

使用过Java开发安卓App的童鞋肯定用过ListView,它灵活多变的设计方式与思路,对于我这样从Delphi转来的人而言,深有启迪。本文的忠旨是通过介绍Java中Adapter的用法,来让不了解这方面的童鞋学习其中的设计思想。

ListView是真正的数据与界面完全分离的设计思路,UI由Android标准的XML方式随意搭配,定制显式效果,这种UI设计思想,确实很先进。不过本文主要讲的是数据适配器(Adapter),所以UI方面下回有机会再说。

在Android开发中(java),每个ListView都有自己的Adapter。ListView要显示什么内容,完全由这个数据适配器控制。ADK为数据适配器规定了标准的接口BaseAdapter,它规定了需要用到的标准接口,我们在开发中,只需要继承(extends)BaseAdapter产生一个新类,就可以在里面写自己的代码了。下面我贴出一个基本的可以用来显示字符串列表的Adapter:

	/**
	 * 数据适配器
	 * @author YangYxd
	 */
	public class ListViewAdapter extends BaseAdapter{
		protected LayoutInflater mInflater; 
		private List<String> list;

		public ListViewAdapter(Context context, List<String> list) {
			this.mInflater = LayoutInflater.from(context); 
			this.list = list;
		}

		@Override
		public int getCount() {
			return list.size();
		}

		@Override
		public Object getItem(int position) {
			return list.get(position);
		}

		@Override
		public long getItemId(int position) {
			return position;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
        ...
		    return convertView; 
		}	
	}

上面的代码,是一个最简单的自定义Adapter,实现了最主要的接口:getCount()、getItem()、getItemId()和getView()。来看看这几个主要接口的作用:

  • getCount():返回数据的行数。就是由它来控制ListView显示的数据一共有几条。
  • getItem(): 获取一个Item。在使用lstView.getItemAtPosition(position)这样的功能时,会调用getItem()返回具体的数据。
  • getItemId(): 获取一个Item的ID。和getItem()类似用途,只不过它一般用来返回数据的ID字段。实际开发中,往往直接返回position,也就是索引号。
  • getView():这个是重中之重了。由它来指定ListView中每一行的数据到底怎么显示。下面我们详细的说说getView。

经常在自定义Adapter时,会有类似下面的getView():

 

/** 视图所有者 */
public static class ListViewHolder{
  public TextView tvTitle;
}

 

@Override
public View getView(int position, View convertView, ViewGroup parent) {
  ListViewHolder holder = null; 
  final String value = list.get(position);

  if (convertView != null && convertView.getTag() != null) 
    holder = (ListViewHolder)convertView.getTag();

  if (holder == null) {
      holder = new ListViewHolder(); 
      convertView = mInflater.inflate(R.layout.lst_item_view, null); // 加载一个XML界面
      holder.tvTitle = (LinearLayout) convertView.findViewById(R.id.tvTitle);	// 得到tvTitle这个控件用于显示文本	    
      convertView.setTag(holder);
  }
  holder.tvTitle.setText(value);
  return convertView; 
}	

lst_item_view.xml:

<LinearLayout 
  android:orientation="vertical" 
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  xmlns:android="http://schemas.android.com/apk/res/android">

    <TextView
        android:id="@+id/tvTitle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="4dp"
        android:layout_marginRight="8dp"
        android:background="@drawable/chatfrom_bg" />

</LinearLayout>

完成了ListViewAdapter,只需要new一个实例,然后

adapter = new ListViewAdapter(context);
lstView.setAdapter(adapter);

这样,ListView就可以使用我们的数据适配器显示内容了。 上面的这段getView()代码还应用了缓存技术,避免每次都去加载XML和获取tvTitle。实际上在getView可以很复杂,比如Item不再是一个字符串,而是一个类,类中包含了各种数据,如大小,金额等。还可以根据不同的Item,返回不同的convertView,做出一个ListView显示多种效果的样子,如Android QQ的“我”栏目,上面是功能,下面是数据等。
除了ListView,在使用Java进行Android开发中,很多地方都用了数据适配器方式。数据与UI完全分离,让程序变得很灵活,UI部分不需要占用内存去存放数据,处理数据的代码也可以专心的处理数据而不去管UI怎么显示。在数据变化后,只需要适时的调用一下notifyDataSetChanged()函数界面就会更新显示了。
上面说了在Java中Adapter的基本功能与用法,玩Delphi的童鞋可能已经发现了,它和我们的ListBox将Style设置成lbVirtualOwnerDraw时原理差不多。不过ADK做的更加成熟,更加实用了。它的设计思想,很值得我们学习。

 

分享到: