天天看點

android adapter中到converView機制

以前一直在用BaseAdapter,對于其中的getview方法的重寫一直不太清楚。今天終于得以有空來探究它的詳細機制。

下面先講講我遇到的幾個問題:

一.View getview(int position, View convertview, ViewGroup parent )中的第二個參數是什麼含義;

二.View的SetTag和getTag方法的用途;

先來解決第一個問題:

android SDK中這樣講參數 convertview :

the old view to reuse, if possible. Note: You should check that this view is non-null and of an appropriate type before using.

 If it is not possible to convert this view to display the correct data, this method can create a new view.

翻譯:

如果可以的話,這是舊View(這裡不便翻譯有的人翻成視圖)的重用。 建議:在用之前,你應該檢查這個View是

不是非空,是不是一個合适的類型。

如果不可能讓這個VIew去顯示一個恰當的資料,這個方法會建立一個新的View。

如果我們要做的是一個ListView,在手機上顯示的隻有那麼幾條Item,而整個ListView可能有很長,可能是100條

甚至是上萬條,總不能讓這麼多條Item都駐留在記憶體中,是以android為你準備了一套機制,就是Recycler(反複循

環器),他的具體工作原理可以到 http://www.cnblogs.com/xiaowenji/archive/2010/12/08/1900579.html去看。

但是有些地方他沒有講清,是以我再講一下。先把代碼貼出來

布局檔案main.xml

[java] view plain copy print ?

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:orientation="vertical" >  
  6.     <ListView  
  7.         android:id="@+id/result"  
  8.         android:layout_width="fill_parent"  
  9.         android:layout_height="fill_parent"  
  10.         android:cacheColorHint="#00000000" >  
  11. </ListView>  
  12. </LinearLayout>  
<?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" >
    <ListView
        android:id="@+id/result"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:cacheColorHint="#00000000" >
</ListView>
</LinearLayout>
           

此處注意ListView的android:layout_height屬性值為"fill_paternt",如果為“wrap_content"将會是另一種情況

adapter的代碼ListViewAdapter.java 

[java] view plain copy print ?

  1. class ListViewAdapter extends BaseAdapter  
  2.    {  
  3.         private Context mContext;  
  4.         int i=0;  
  5.         public ListViewAdapter (Context context)  
  6.         {  
  7.             this.mContext=context;  
  8.         }  
  9.     @Override  
  10.     public int getCount()  
  11.     {  
  12.         return 30;  
  13.     }  
  14.     @Override  
  15.     public Object getItem(int position)  
  16.     {  
  17.                 return position;  
  18.     }  
  19.     @Override  
  20.     public long getItemId(int position)  
  21.     {  
  22.                 return 0;  
  23.     }  
  24.     @Override  
  25.     public View getView(int position, View convertView, ViewGroup parent)  
  26.     {  
  27.          System.out.println("getView " + position + " " + convertView);//調試語句  
  28.          Holder holder;  
  29.         if(null==convertView)  
  30.         {  
  31.             holder=new Holder();  
  32.             convertView=LayoutInflater.from(mContext).inflate(R.layout.textview, null); //mContext指的是調用的Activtty  
  33.             holder.textView=(TextView)convertView.findViewById(R.id.textview);  
  34.             convertView.setTag(holder);  
  35.         }  
  36.         else  
  37.         {  
  38.             holder=(Holder)convertView.getTag();  
  39.         }  
  40.         holder.textView.setText("position: "+position);  
  41.             return convertView;           
  42.     }  
  43.     class Holder  
  44.     {  
  45.         public TextView textView;  
  46.     }  
  47.     }  
class ListViewAdapter extends BaseAdapter
   {
    	private Context mContext;
    	int i=0;
    	public ListViewAdapter (Context context)
    	{
    		this.mContext=context;
    	}
	@Override
	public int getCount()
	{
		return 30;
			
	}
	@Override
	public Object getItem(int position)
	{
                return position;
	}
	@Override
	public long getItemId(int position)
	{
                return 0;
	}
    @Override
	public View getView(int position, View convertView, ViewGroup parent)
	{
         System.out.println("getView " + position + " " + convertView);//調試語句
         Holder holder;
		if(null==convertView)
		{
			holder=new Holder();
			convertView=LayoutInflater.from(mContext).inflate(R.layout.textview, null); //mContext指的是調用的Activtty
			holder.textView=(TextView)convertView.findViewById(R.id.textview);
			convertView.setTag(holder);
		}
		else
		{
			holder=(Holder)convertView.getTag();
		}
		holder.textView.setText("position: "+position);
	        return convertView;  	    
	}
	class Holder
	{
		public TextView textView;

	}
    }
           

運作程式之後發現螢幕上顯示出的Item的convertview都為空,向下滑動新産生的Item的convetview都不為空。到此為止和上面連結中講的是一緻的,但是如果設定ListView的android:layout_height屬性值為“wrap_content

之後,發現隻有第一個Item的convertview為null其他的不為空。

雖然兩種設定不同,結果也不同,但是convertview的機制沒有變。

其實到此為止我們可以總結出convertview的機制了,就是在初始顯示的時候,每次顯示一個item都調用一次getview方法但是每次調用的時候covertview為空(因為還沒有舊的view),當顯示完了之後。如果螢幕移動了之後,并 且導緻有些Item(也可以說是view)跑到螢幕外面,此時如果還有新的item需要産生,則這些item顯示時調用的getview方法中的 convertview參數就不是null,而是那些移出螢幕的view(舊view),我們所要做的就是将需要顯示的item填充到這些回收的 view(舊view)中去,最後注意convertview為null的不僅僅是初始顯示的那些item,還有一些是已經開始移入螢幕但是還沒有 view被回收的那些item。

最終我們用親手寫的代碼實作了Recycler(反複循環器).

第二個問題其實應該在第一個問題中嵌套來講,但是為了思路清晰我分開了:

view的setTag和getTag方法其實很簡單,在實際編 寫代碼的時候一個view不僅僅是為了顯示一些字元串、圖檔,有時我們還需要他們攜帶一些其他的資料以便我們對該view的識别或者其他操作。于是 android 的設計者們就創造了setTag(Object)方法來存放一些資料和view綁定,我們可以了解為這個是view 的标簽也可以了解為view 作為一個容器存放了一些資料。而這些資料我們也可以通過getTag() 方法來取出來。

到這裡setTag和getTag大家應該已經 明白了。再回到上面的話題,我們通過convertview的setTag方法和getTag方法來将我們要顯示的資料來綁定在convertview 上。如果convertview 是第一次展示我們就建立新的Holder對象與之綁定,并在最後通過return convertview 傳回,去顯示;如果convertview 是回收來的那麼我們就不必建立新的holder對象,隻需要把原來的綁定的holder取出加上新的資料就行了。

至此我的問題講完了,你的問題解決了麼?