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()方法这里就不说了,网上有很多,等自己掌握了之后,再补上吧。