getChildAt(index)方法ViewGroup類的方法,許多需要adapter的類(List,GridView)都可以使用這個方法。今天就用到了getChildAt(index)方法,我用的是GridView,需要在數據庫中讀出GridView中的某些項目,給這些子項替換背景(就是打個勾標記的背景),但是,卻發現getChildAt(index)方法返回值一直為null,很是不理解。
下面做個demo重現該問題:
java代碼:
1 import java.util.ArrayList; 2 import java.util.HashMap; 3 import java.util.Map; 4 5 import android.os.Bundle; 6 import android.app.Activity; 7 import android.graphics.Color; 8 import android.util.Log; 9 import android.widget.GridView; 10 import android.widget.SimpleAdapter; 11 12 public class MainActivity extends Activity { 13 14 ArrayList<Map<String,Object>> list = new ArrayList<Map<String,Object>>(); 15 SimpleAdapter adapter; 16 GridView gv; 17 18 @Override 19 public void onCreate(Bundle savedInstanceState) { 20 super.onCreate(savedInstanceState); 21 setContentView(R.layout.activity_main); 22 gv = (GridView)findViewById(R.id.gv); 23 gv.setNumColumns(7); 24 gv.setVerticalSpacing(50); 25 26 final String [] number = new String[] 27 { 28 "1","2","3","4","5","6","7","8","9","10", 29 "11","12","13","14","15","16","17","18","19","20" 30 }; 31 final ArrayList<Map<String,Object>> list = new ArrayList<Map<String,Object>>(); 32 33 for(int i=0;i<number.length;i++) 34 { 35 Map<String,Object> listitem = new HashMap<String,Object>(); 36 listitem.put("id", number[i]); 37 list.add(listitem); 38 } 39 40 41 adapter = new SimpleAdapter(this 42 ,list 43 ,R.layout.list 44 ,new String[]{"id"} 45 ,new int[]{R.id.tv}); 46 gv.setAdapter(adapter); 47 // Log.v("gv.getChildAt(5)", ""+gv.getChildAt(5)); (1) 48 // gv.getChildAt(5).findViewById(R.id.tv).setBackgroundColor(Color.BLUE); (2) 49 } 50 }
xml布局文件:
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 android:layout_width="match_parent" 3 android:layout_height="match_parent" > 4 5 <GridView 6 android:id="@+id/gv" 7 android:layout_width="fill_parent" 8 android:layout_height="wrap_content" 9 /> 10 11 </RelativeLayout>
list.xml
<RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android"> <TextView android:id="@+id/tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:textColor="#000000" /> </RelativeLayout>
以上程序將正常運行:
然后將上面注釋的兩行代碼去掉,程序出錯:
正如上面所說是空指針錯誤,看代碼(1)那行的輸出:
百思不得其解之后,請來UI組的師傅給找原因,他用了Handler類實現了:(把上面java代碼中注釋掉的兩行代碼,換成以下代碼)
1 Handler handler = new Handler(); 2 handler.postDelayed(new Runnable() { 3 public void run() { 4 // TODO Auto-generated method stub 5 gv.getChildAt(5).findViewById(R.id.tv).setBackgroundColor(Color.BLUE); 6 } 7 }, 500);
運行結果:
師傅說是因為setadapter()方法不是立即就執行好的,而是要用到計算機時間片輪轉的規則,所以稍微延遲執行后面的getChildAt(index)方法,就不會返回null了。但是,做產品的時候,這種延遲的方法也不是合適的方法,萬一用戶后台執行了大量程序,CPU工作的效率很低,幾個時間片都沒有完成setadapter()方法,這就成為了bug,如果把延遲時間拉長,又會影響用戶體驗。
所以,一般情況下,要改變GridView的某一項的狀態(改變背景等),而這種改變並不是隨事件觸發(click事件,select事件等),而是一開始就有(如從數據庫中讀取),那么應該自定義adapter,重寫它的getView()方法,以便直接在setadapter()時就完成要做的事,不用在代碼中手動更改。如果需要動態改變,onItemXXXListener方法中可以實現。
由於這次的困擾,也發現自己對適配器的工作原理還是十分的不熟悉,實現重寫adapter的getView()方法,也是參考了別人已經做好的東西,所以實現重寫adapter的getView()方法這里就不說了,網上有很多,等自己掌握了之后,再補上吧。