Android用户界面 UI组件--AdapterView及其子类(一) ListView及各种Adapter详解

分享到:

ListView就是列表组件,一般通过继承ListActivity使用系统提供的ListView.

所有的AdapterView组件都需要有一个对应的Adapter作为适配器来显示列表中元素的布局方式

见思维导图


ArrayAdapter: 数组或集合的适配器。

例:
private final String[] mous = {
        "郭嘉",
        "荀攸",
        "荀彧",
        "程昱",
        "戏志才",
        "徐庶"
};
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,mous);


也可以在XML文件中用android:entries属性指定绑定的数组资源文件
资源文件存放在value文件夹下
如:
android:entries="@array/book"

<string-array name="book" >
        <item >1</item>
        <item >2</item>
        <item >3</item>
        <item >3</item>
</string-array>   


例子

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal" >

    <ListView
        android:id="@+id/lv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

</LinearLayout>

 

package com.light.android.study;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.ListView;

public class MainActivity extends Activity {
		
	    private final String[] mous = {
	      "郭嘉",
	      "荀攸",
	      "荀彧",
	      "程昱",
	      "戏志才",
	      "徐庶"
	    };
	    private ListView lv;
	    
		@Override
		public void onCreate(Bundle savedInstanceState)
		{
			super.onCreate(savedInstanceState);
			setContentView(R.layout.activity_main);
			init();
			initAdapter();
		}

		private void init(){
			lv = (ListView) findViewById(R.id.lv);
		}
		
		private void initAdapter(){
           ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,mous);
           lv.setAdapter(adapter);
		}
		
}


效果:

 



SimpleAdapter:简单的Adapter实现

SimpleAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to)
第一个参数是Context对象
第二个参数是保存有每一行数据的Map构成的List对象,也就是说,每一行数据里的每一个属性都由它的名字和它的值构成一个键值对,多个属性有多个键值对,每一行的多个键值对构成这一行的一个Map对象,这一行的Map对象对应到这个List中.
第三个参数布局文件Id
第四个参数Map对象中的多个键值对的key值
第五个参数布局文件中用来显示内容的组件ID


SimpleAdapter绑定数据到视图分两个阶段
1.首先,如果设置了SimpleAdapter.ViewBinder,那么这个设置的ViewBinder的setViewValue(android.view.View, Object, String)将被调用.如果setViewValue的返回值是true,则表示绑定已经完成,将不再调用系统默认的绑定实现.
2.如果返回值为false,视图将按以下顺序绑定数据:
•如果View实现了Checkable(例如CheckBox),期望绑定值是一个布尔类型.
•TextView.期望绑定值是一个字符串类型,通过调用setViewText(TextView, String)绑定.
•ImageView,期望绑定值是一个资源id或者一个字符串,通过调用setViewImage(ImageView, int) 或 setViewImage(ImageView, String)绑定数据.
如果没有一个合适的绑定发生将会抛出IllegalStateException.

例子:

布局文件:

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <!-- 定义一个List -->

    <ListView
        android:id="@+id/mylist"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
    
</LinearLayout>

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <!-- 定义一个ImageView,用于作为列表项的一部分。 -->

    <ImageView
        android:id="@+id/header"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingLeft="10dp"
        tools:ignore="ContentDescription" />

    <!-- 定义一个TextView,用于作为列表项的一部分。 -->

    <TextView
        android:id="@+id/name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:paddingLeft="10dp"
        android:textSize="16sp" />

</LinearLayout>

 

package com.light.android.study;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;
import android.widget.SimpleAdapter;

public class MainActivity extends Activity {
	private String[] names = new String[] { "杜甫", "弄玉", "清照", "李白" };
	private int[] imageIds = new int[] { R.drawable.tiger, R.drawable.nongyu,
			R.drawable.qingzhao, R.drawable.libai };

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		List<Map<String, Object>> listItems = new ArrayList<Map<String, Object>>();
		for (int i = 0; i < names.length; i++) {
			Map<String, Object> map = new HashMap<String, Object>();
			map.put("header", imageIds[i]);
			map.put("personName", names[i]);
			listItems.add(map);
		}
		
		//創建SimpleAdapter
		SimpleAdapter simpleAdapter = new SimpleAdapter(this, listItems,
				R.layout.list_item_layout, new String[] { "personName", "header" },
				new int[] { R.id.name, R.id.header });
		
		ListView list = (ListView) findViewById(R.id.mylist);
		list.setAdapter(simpleAdapter);
	}
}


效果:

 



CursorAdapter:

 

Cursor型集合的适配器,与数据库连接的桥梁
其中游标携带的结果集中必须有列名为“_id”的列,否则这个类无法工作.
getView()
每一项显示的设置
bindView()
把数据和已经生成的View绑定在一起
newView()
新建一个View
CursorAdapter中源码 getView的实现
public View getView(int position, View convertView, ViewGroup parent) {
 View v;
 if (convertView == null) {
   v = newView(mContext, mCursor, parent);
 } else {
   v = convertView;
 }
 bindView(v, mContext, mCursor);
 return v;
}
getView首先使用已经存在的View,如果没有就调用newView 产生一个,然后把数据bind上去

我们一般使用其子类SimpleCursorAdapter来实现查询出来的数据List的Adapter

SimpleCursorAdapter(Context context,int layout,Cursor c,String[] from,int[] to,int flags)
context:当前Context对象
layout:布局文件Id
c:集合
from:需要绑定的集合中的列的名字
to:显示项目的View的id集合,在layout布局文件中定义
flags:用来判断适配器的行为标志
建议使用CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER
适配器会在游标上注册一个内容观测器,当通知到达时会调用 onContentChanged() 方法.使用该标志位时要注意:在注册观察器时需要先解除当前游标与适配器的关联,防止发生泄漏.
Android 3.0引入了CursorLoader实现异步加载数据,为了避免同步查询数据库时阻塞UI线程的问题。所以一般先将SimpleCursorAdapter中的Cursor对象放空,然后用CursorLoader对象加载数据,再放入适配器。
例子:

布局文件:

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal" >

    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

</LinearLayout>

Item布局文件:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:tools="http://schemas.android.com/tools"
              android:layout_width="match_parent" 
              android:layout_height="64dip" 
              android:orientation="horizontal" 
              android:gravity="center_vertical" 
              android:paddingLeft="8dip">
               
               <TextView android:id="@android:id/text1" 
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content" 
                         android:textSize="18sp" 
                         android:gravity="center_vertical" 
                         android:singleLine="true" 
                         android:fadingEdge="horizontal" 
                         android:fadingEdgeLength="3dip" 
                         android:ellipsize="marquee" 
                         /> 
</LinearLayout>

 

 

package com.light.android.study;

import android.app.ListActivity;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.Context;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.widget.SimpleCursorAdapter;

   //實現接口作為CursorLoader
public class MainActivity extends ListActivity implements LoaderCallbacks<Cursor> {
	private SimpleCursorAdapter mAdapter;
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		// Create an empty adapter we will use to display the loaded data. 
		mAdapter = new SimpleCursorAdapter(MainActivity.this,
				R.layout.contacts_list_item, null,
				new String[] { ContactsContract.Contacts.DISPLAY_NAME },
				new int[] { android.R.id.text1 },
				0);
		
		getListView().setAdapter(mAdapter);
		
		//初始化Loader
		//第一個參數 為這個Loader對象指定唯一的标识ID,第二个可选参数,用来支持Loader的构造方法,
		//第三个参数是LoaderCallbacks接口类型
		getLoaderManager().initLoader(0, null, this);
	}

	public Loader<Cursor> onCreateLoader(int id, Bundle args) {
		// 去数据库读取数据等要消耗大量时间的操作放在 
		// 自定义 CursorLoader 的 onLoadInBackground
		return new MyCursorLoader(getApplicationContext());
	}

	
	public void onLoadFinished(Loader<Cursor> arg0, Cursor cursor) {
		// Swap the new cursor in.  (The framework will take care of closing the         
		// old cursor once we return.) 
		mAdapter.swapCursor(cursor); 
	}

	public void onLoaderReset(Loader<Cursor> arg0) {
		// This is called when the last Cursor provided to onLoadFinished()        
		// above is about to be closed.  We need to make sure we are no         
		// longer using it. 
		mAdapter.swapCursor(null);
	}

	public static class MyCursorLoader extends CursorLoader {
		String[] mContactProjection = { ContactsContract.Contacts._ID,
				ContactsContract.Contacts.DISPLAY_NAME };
		private Context mContext;

		public MyCursorLoader(Context context) {
			super(context);
			mContext = context;
		}

		/**
		 * 4.自定义 CursorLoader 的 onLoadInBackground
		 * 会返回一个Cursor,这里给SimpleCursorAdapter用 
		 * 来填充数据。查询数据等操作放在这里执行
		 */
		@Override
		protected Cursor onLoadInBackground() {
			Cursor cursor = mContext.getContentResolver().query(
					ContactsContract.Contacts.CONTENT_URI, mContactProjection,
					null, null, null);
			return cursor;
		}
	}
}


效果:

 


最后看下自定义BaseAdapter

需要实现下列方法:

abstract Object getItem(int position)
得到位于position位置的项
abstract int getCount()
得到项目总数
abstract long getItemId(int position)
得到位于position位置的项的Id
abstract int getItemViewType(int position)
得到位于position位置的项的类型
abstract View getView(int position,View convertVeiw,ViewGroup parent)
每一项显示的设置
在getView方法中需要缓存加载View优化ListView

官方建议使用ViewHolder,其实就是单例
例:

 

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
 ViewHolder holder; 
 if (convertView == null) {
     final LayoutInflater inflater = (LayoutInflater)                        mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     convertView = inflater.inflate(R.layout.list_item_icon_text, null); 
      holder = new ViewHolder();  
      holder.icon = (ImageView) convertView.findViewById(R.id.icon); 
      holder.text = (TextView) convertView.findViewById(R.id.text); 
      convertView.setTag(holder); 
 } else { 
      holder = (ViewHolder) convertView.getTag(); 
 } 
      holder.icon.setImageResource(R.drawable.icon); 
      holder.text.setText(mData[position]); 
      return convertView; 
} 
static class ViewHolder { 
    ImageView icon; 
    TextView text; 
} 


 







 



 




 

 

昵    称:
验证码:

相关文档: