android getChildAt(index)返回null问题解决方法
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()方法这里就不说了,网上有很多,等自己掌握了之后,再补上吧。