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>

 

  以上程序将正常运行:

android getFilesDir 需要权限么 android getchildat_java

  然后将上面注释的两行代码去掉,程序出错:

android getFilesDir 需要权限么 android getchildat_android试验_02

  正如上面所说是空指针错误,看代码(1)那行的输出:

android getFilesDir 需要权限么 android getchildat_android试验_03

  百思不得其解之后,请来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);

  运行结果:

android getFilesDir 需要权限么 android getchildat_android试验_04

   师傅说是因为setadapter()方法不是立即就执行好的,而是要用到计算机时间片轮转的规则,所以稍微延迟执行后面的getChildAt(index)方法,就不会返回null了。但是,做产品的时候,这种延迟的方法也不是合适的方法,万一用户后台执行了大量程序,CPU工作的效率很低,几个时间片都没有完成setadapter()方法,这就成为了bug,如果把延迟时间拉长,又会影响用户体验。

  所以,一般情况下,要改变GridView的某一项的状态(改变背景等),而这种改变并不是随事件触发(click事件,select事件等),而是一开始就有(如从数据库中读取),那么应该自定义adapter,重写它的getView()方法,以便直接在setadapter()时就完成要做的事,不用在代码中手动更改。如果需要动态改变,onItemXXXListener方法中可以实现。

  由于这次的困扰,也发现自己对适配器的工作原理还是十分的不熟悉,实现重写adapter的getView()方法,也是参考了别人已经做好的东西,所以实现重写adapter的getView()方法这里就不说了,网上有很多,等自己掌握了之后,再补上吧。