Adapter
Adapter做为这个继承结构的最顶层的基接口,定义了Adapter要实现的基本方法:
public interface Adapter {
//注册一个Observer,当Adapter所表示的数据改变时会通知它,DataSetObserver是一个抽象类,定义了两个方法:onChanged与onInvalidated
void registerDataSetObserver(DataSetObserver observer);
//取消注册一个Observer
void unregisterDataSetObserver(DataSetObserver observer);
//所表示的数据的项数
int getCount();
//返回指定位置的数据项
Object getItem(int position);
//返回指定位置的数据项的ID
long getItemId(int position);
//表示所有数据项的ID是否是稳定的,在BaseAdapter中默认返回了false,假设是不稳定的,在CursorAdapter中返回了true,Cursor中的_ID是不变的
boolean hasStableIds();
//为每一个数据项产生相应的视图
View getView(int position, View convertView, ViewGroup parent);
//为了避免产生大量的View浪费内存,在Android中,AdapterView中的View是可回收的使用的。比如你有100项数据要显示,而你的屏幕一次只能显示10条数据,则
//只产生10个View,当往下拖动要显示第11个View时,会把第1个View的引用传递过去,更新里面的数据再显示,也就是说View可重用,只是更新视图中的数据用于显示新
//的一项,如果一个视图的视图类型是IGNORE_ITEM_VIEW_TYPE的话,则此视图不会被重用
static final int IGNORE_ITEM_VIEW_TYPE = AdapterView.ITEM_VIEW_TYPE_IGNORE;
//获得相应位置的这图类型
int getItemViewType(int position);
//getView可以返回的View的类型数量。(在HeaderViewListAdapter中可以包含Header和Footer,getView可以返回Header、Footer及Adapter
//中的视图,但其getViewTypeCount的实现只是调用了内部Adapter的的getViewTypeCount,忽略了Header、Footer中的View Type,不懂。
int getViewTypeCount();
static final int NO_SELECTION = Integer.MIN_VALUE;
boolean isEmpty();
}
以前在用到BaseAadpter显示ListView、GridView、Spinner的时候,直接把网上现成的代码拿过来copy一下,然后修修改改就好了,一直也没有详细地总结一下,今天亲自动手写写,发现还是有不少问题的,先上个图看一下这个程序的运行结果:
利用listview在界面上显示,根据不同的位置,显示不同的图片和文字。
第一步:在建立好工程后,首先来看看主类,BaseAdapterDemoActivity
package com.my;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;
public class BaseAdapterDemoActivity extends Activity
{
private DemoAdapter adapter = null;
private ListView myListView = null;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setView();
}
private void setView()
{
myListView = (ListView) findViewById(R.id.my_listview);
adapter = new DemoAdapter(this);
myListView.setAdapter(adapter);
}
}
这个BaseAdapterDemoActivity很简单,就是new一个适配器,然后把适配器放到listview当中。第二步:BaseAdapterDemoActivity的布局文件main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/my_linearlayout"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ListView
android:id="@+id/my_listview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
</ListView>
<!--<GridView
android:id="@+id/my_gridview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
</GridView>
<Spinner
android:id="@+id/my_spinner"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
</Spinner>
--></LinearLayout>
第三步:为要绘制的每一个条目创建一个布局文件,item_list.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageView
android:id="@+id/myimageview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:src="@drawable/icon"
>
</ImageView>
<TextView
android:id="@+id/mytext"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/name"
/>
</LinearLayout>
最后一步:也是关键所在,BaseAdapter
package com.my;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class DemoAdapter extends BaseAdapter
{
private Context c = null;
private LayoutInflater myInflater = null;
/**
* 构造函数
* @param myContext
*/
public DemoAdapter(Context myContext)
{
c = myContext;
}
@Override
public int getCount()
{
// TODO Auto-generated method stub
return 6;
}
@Override
public Object getItem(int position)
{
// TODO Auto-generated method stub
return position;
}
@Override
public long getItemId(int position)
{
// TODO Auto-generated method stub
return position;
}
/**
* 这个方法getView(),是用来逐一绘制每一条item
*
* setTag()会把View与ViewHolder绑定,形成一一对应的关系,拖动listview的时候会重新绘制每一条item
* 但是那些已经取得绑定的View,会调用getTag()方法,就不会重新绘制,而是拿到内存中已经取得的资源,提高了效率
*
* @param position position就是位置从0开始
* @param convertView convertView是Spinner,ListView中每一项要显示的view
* @param parent parent就是父窗体了,也就是Spinner,ListView,GridView了
* @return 通常return 的view也就是convertView
*/
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
// TODO Auto-generated method stub
ViewHolder holder = new ViewHolder();
if (convertView == null)
{
/**
* 在程序中动态加载以上布局:
* LayoutInflater flater = LayoutInflater.from(this);
* View view = flater.inflate(R.layout.example, null);
*/
myInflater = LayoutInflater.from(c);
convertView = myInflater.inflate(R.layout.item_list, null);
holder.icon = (ImageView) convertView
.findViewById(R.id.myimageview);
holder.text = (TextView) convertView.findViewById(R.id.mytext);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder) convertView.getTag();
}
if (position <= 1)
{
holder.icon.setImageResource(R.drawable.icon);
holder.text.setText(R.string.text1);
}
else if (position <= 3 && position >= 2)
{
holder.icon.setImageResource(R.drawable.icon_b);
holder.text.setText(R.string.text2);
}
else
{
holder.icon.setImageResource(R.drawable.icon_c);
holder.text.setText(R.string.text3);
}
return convertView;
}
private class ViewHolder
{
TextView text;
ImageView icon;
}
}
在这段代码中有几点还是需要特别提出来:
1.构造函数public DemoAdapter(Context myContext)可以不用创建,这个创建是因为LayoutInflater需要一个Context;
2.方法public int getCount()是用来说明需要绘制的条目数量,这里是6条;
3.方法public View getView(int position, View convertView, ViewGroup parent)用来逐条绘制,也就是说每绘制一个条目就调用一次这个方法;
4.setTag() getTag()等在代码的注释中加了解释。