一、ListView的基本用法

列表的显示需要三个元素:

1. ListView:用来展示列表的View。

2. Adapter适配器:是ListView界面与数据之间的桥梁;即用来把数据映射到ListView上的中介;当列表里的每一项显示到页面时,都会调用Adapter的getView方法返回一个View。

3. 数据:具体的将被映射的字符串、图片或基本组件等。

根据列表适配器的类型,可分为三种:ArrayAdapter,SimpleAdapter和CursorAdapter。其中ArrayAdapter最为简单,只能展示一行字。SimpleAdapter可用于显示自定义的复杂布局文件。SimpleCursorAdapter可以认为是SimpleAdapter对数据库的简单结合,可以方便的把数据库的内容以列表的形式展示出来。SimpleAdapter虽说已经可以满足大多数情况的需要,但还不够灵活,用SimpleAdapter显示的每一行布局都是相同的,不能有特殊情况。因此如果希望可以扩展ListView的显示特性,比如使一些行布局发生变化,或者添加Button控件的响应等,这时候就要自己去实现一个BaseAdapter,通过其getView方法为每一行返回特定的布局形式或者视图。例如

系统要绘制ListView,首先用getCount()函数得到要绘制的列表的长度,然后开始绘制第一行,如何绘制呢?调用getView()函数。在这个函数里首先获得一个View(如果是一个简单的显示则是View,如果是一个自定义的里面包含较多控件的时候它其实是一个ViewGroup),然后再实例化并设置各个组件及其数据内容并显示它。绘制完这行后,依此再绘制完。

二、ListView加载数据的基本原理

ListView针对每个item,要求Adapter返回一个视图(getView),即ListView在开始绘制时,系统首先调用getCount()函数,根据他的返回值得到ListView的长度,然后根据该长度,调用getView()一行一行的绘制ListView的每一项。如果getCount()返回值是0的话,列表一行都不会显示,如果返回1,就只显示一行;返回几则显示几行。如果我们有成千上万的item要显示怎么办呢?为每个item创建一个新的View?这是不可能的!实际上Android早就缓存了这些视图;Android中有个Recycler的构件。只有可见的项目存在内存中,其他的在Recycler中。

三、ListView的优化

list.xml



<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
		android:layout_width="fill_parent"
		android:layout_height="fill_parent"
		android:orientation="vertical">
	<LinearLayout 
		android:id="@+id/linearLayout1" 
		android:layout_width="fill_parent"
		android:layout_height="wrap_content" 
		android:orientation="horizontal">
		
		<ImageView 
			android:layout_height="wrap_content"
			android:layout_width="wrap_content"
			android:src="@drawable/icon"
			android:id="@+id/imageView1"
			android:layout_margin="5px">
		</ImageView>
		
		<TextView 
			android:text="TextView"
			android:id="@+id/textView1"
			android:layout_width="wrap_content" 
			android:layout_height="wrap_content"
			android:layout_gravity="center"
			android:textSize="20px">
		</TextView>
	
	</LinearLayout>
	
</LinearLayout>



1. 最简单的方法,最慢且最不实用。



1 @Override
 2     public View getView(int position, View convertView, ViewGroup parent) {
 3        // TODO Auto-generated method stub
 4        //找到R.layout.list布局文件
 5        layout_Adapter = (LinearLayout)this.layoutInflater.inflate(R.layout.list, null);
 6        imageView = (ImageView)layout_Adapter.findViewById(R.id.imageView1);
 7        textView = (TextView)layout_Adapter.findViewById(R.id.textView1);
 8        imageView.setImageResource(R.drawable.icon);
 9        textView.setText(title[position]);
10        return layout_Adapter;
11     }



2. View的重用。View的每次创建都是比较耗时的,利用convertview回收视图;即对于getview方法传入的convertView做 != null的判断;这样系统将会少创建很多View,性能得到了很大的提升。



1 @Override
 2     public View getView(int position, View convertView, ViewGroup parent) {
 3        // TODO Auto-generated method stub
 4        if(convertView == null){
 5            convertView = (LinearLayout)this.layoutInflater.inflate(R.layout.list, null);
 6        }
 7        imageView = (ImageView)convertView.findViewById(R.id.imageView1);
 8        textView = (TextView)convertView.findViewById(R.id.textView1);
 9        imageView.setImageResource(R.drawable.icon);
10        textView.setText(title[position]);
11        return convertView;
12     }



3. ViewHolder的应用。View的findViewById()方法也是比较耗时的,因此需要考虑只调用一次,之后就用View.getTag()方法来获得ViewHolder对象。



1 public View getView(int position, View convertView, ViewGroup parent) {
 2        // TODO Auto-generated method stub
 3        ViewHolder holder;
 4        if(convertView == null){
 5            convertView = (LinearLayout)this.layoutInflater.inflate(R.layout.list, null);
 6            holder = new ViewHolder();
 7            holder.tv = (TextView)convertView.findViewById(R.id.textView1);
 8            holder.im = (ImageView)convertView.findViewById(R.id.imageView1);
 9            convertView.setTag(holder);
10        }else{
11            holder = (ViewHolder)convertView.getTag();
12            Log.d("list", "convertView....");
13        }
14        holder.im.setImageResource(R.drawable.icon);
15        holder.tv.setText(title[position]);
16        return convertView;
17     }
18  
19     static class ViewHolder{
20        TextView tv;
21        ImageView im;
22     }



这种方法为View设置了Tag属性,通过setTag()方法将View的ImageView、TextView组件的对象添加到Tag 中,当回收利用时直接用getTag()方法取出,不需要重新获取组件。

 

ListView的优化三原则

1.复用convertView。

在getItemView中,判断convertView是否为空,如果不为空,可复用。

2.异步加载图片

item中如果包含有webimage,那么最好异步加载

3.快速滑动时不显示图片

当快速滑动列表时(SCROLL_STATE_FLING),item中的图片或获取需要消耗资源的view,可以不显示出来;而处于其他两种状态(SCROLL_STATE_IDLE 和SCROLL_STATE_TOUCH_SCROLL),则将那些view显示出来;在做ListView加载数据时如果数据量大的话会造成加载时间过长而卡屏,所以为了解决这个问题,查看了SDK,在OnScrollListener中有两个方法只要重写这两个方法就可以实现滚动加载,例如:



1 public void onScroll(AbsListView v, int firstVisibleItem,    int visibleItemCount, int totalItemCount) {  
 2 
 3    lastItem = firstVisibleItem + visibleItemCount - 1;   
 4 
 5   if (adapter.count == lastItem) {    
 6 
 7   adapter.count += 10;    adapter.notifyDataSetChanged();  
 8 
 9    }
10 }
11 public void onScrollStateChanged(AbsListView view, int scrollState) {   
12 
13 // TODO Auto-generated method stub
14   Log.i("onScrollStateChanged", "onScrollStateChanged"); 
15 
16 }