最近在使用android的组件ExpandableListView,实现需求时,遇到不少奇怪的问题。

我的需求就是在ExpandableListView的父一级的view上添加两个按钮,实现添加子一级view的添加一级删除自己的功能。

自定义的layout如下:

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/layout_parentView"    android:layout_width="fill_parent"    android:layout_height="wrap_content" >    <ImageView        android:id="@+id/iv_flag"        android:layout_width="10dp"        android:layout_height="10dp"        android:layout_alignParentLeft="true"        android:layout_centerVertical="true"        android:layout_marginLeft="5dp"        android:focusable="false" />    <TextView        android:id="@+id/tv_typename"        android:layout_width="100dp"        android:layout_height="30dp"        android:layout_centerInParent="true"        android:layout_marginLeft="10dp"        android:focusable="false" />    <ImageButton        android:id="@+id/iv_dele"        android:layout_width="40dp"        android:layout_height="40dp"        android:layout_alignParentRight="true"        android:layout_centerVertical="true"        android:layout_marginRight="5dp"        android:src="@drawable/del"         android:focusable="false"/>    <ImageButton        android:id="@+id/iv_add"        android:layout_width="40dp"        android:layout_height="40dp"        android:layout_marginRight="10dp"        android:layout_toLeftOf="@id/iv_dele"        android:src="@drawable/add"         android:focusable="false"/></RelativeLayout>

GroupView部分的Java代码如下:

@Overridepublic View getGroupView(int groupPosition, boolean isExpanded,View convertView, ViewGroup parent) {View parentView = null;if(groupViews.size()>groupPosition){parentView = groupViews.get(groupPosition);} else {parentView = newParentView(groupPosition);groupViews.add(parentView);}return parentView;}private View newParentView(int groupPosition){ View parentView = li_parent.inflate(R.layout.list_parent_view, null);TextView textview = (TextView) parentView.findViewById(R.id.tv_typename);BigType bt = groupList.get(groupPosition);textview.setText(bt.getName());View v_dele = parentView.findViewById(R.id.iv_dele);v_dele.setTag(bt.getName());v_dele.setOnClickListener(new BtnDeleBigTypeListener(ct));View v_add = parentView.findViewById(R.id.iv_add);v_add.setTag(bt.getName());v_add.setOnClickListener(new BtnAddSmallTypeListener(ct));return parentView;}

当Activity加载该layout后,当没有展开子一级,父一级上的两个ImageButton按钮均点击正常,可是当点开子一级后,点击两个ImageButton,均得不到立即的响应 非得再产生了其他控件的点击事件(例如点击父一级,让其收起)后,之前点击 ImageButton的事件才会得到响应。一开始感觉是事件响应队列阻塞,可是为啥在产生新的事件后,所有的事件又会马上得到响应呢?

先做一个测试,代码见下,代码里的ViewHolder是一个自定义的类,也是后面ViewHolder模式的主要体现,这里先卖一关子...

View cache = null;       @Overridepublic View getGroupView(int groupPosition, boolean isExpanded,View convertView, ViewGroup parent) {ViewHolder _vh = null;if(convertView == null){ _vh = new ViewHolder();convertView = newParentView(_vh);convertView.setTag(_vh);cache = convertView;} else {_vh = (ViewHolder) convertView.getTag();if(cache.equals(convertView)){Log.i(TAG, "equals old obj");}}return convertView;}

上面代码主要就是想测试converView,究竟是拿来干什么的,google文档里头做了如此解析:


大致意思就是在重复利用此物之前要检查其是否为null!可是就没说清楚,这个convertView究竟是什么时候会存在!

现在来看看测试的结果,ExpandableListView总共有4个父节点,但是有以下三次输出结果:


这表明,ExpandableListView每次都在重画通过getGroupView拿到的View,而且只创建一次,之后都是都是同一个!这下子明白了,前面不能响应的按钮点击事件,原来是convertView这一覆盖层在搞鬼!因为我在代码里头每次都是在newPareView的,结果原来的convertView还在,结果就盖住了新的view,导致事件流分派出现问题,当再有convertView以外的事件发生,或ExpandableListView刷新,事件流恢复正常,响应也就正常了...

看来有时候真的要好好研究理解清楚API更深层次的用意才好做开发 啊!

不过话又说回来,其实ExpandableListView(包括ListView)的这个convertView是很有用的,因为ExpandableListView只是根据getGroupView返回的view去画列表,但是一般list列表的内容在同一级基本都会有共通性,只是加载的信息内容不同,所以重用convertView,可以很大程度上提升ListView的性能,特别是在加载大数据量时。这里配合ViewHolder模式,就可以更好地对久对象进行重用了!

下面是改良过得代码:

@Overridepublic View getGroupView(int groupPosition, boolean isExpanded,View convertView, ViewGroup parent) {ViewHolder _vh = null;if(convertView == null){ _vh = new ViewHolder();convertView = newParentView(_vh);convertView.setTag(_vh);} else {_vh = (ViewHolder) convertView.getTag();}BigType bt = groupList.get(groupPosition);String name = bt.getName();_vh.getTitle().setText(name);ImageButton _btn_dele = _vh.getBtn_dele();_btn_dele.setTag(name);_btn_dele.setFocusable(false);_btn_dele.setClickable(true);_btn_dele.setOnClickListener(new BtnDeleBigTypeListener(ct));ImageButton _btn_add = _vh.getBtn_add();_btn_add.setTag(bt.getName());_btn_add.setFocusable(false);_btn_add.setClickable(true);_btn_add.setOnClickListener(new BtnAddSmallTypeListener(ct));return convertView;}private View newParentView(ViewHolder vh){View parentView = li_parent.inflate(R.layout.list_parent_view, null);ImageView iv_flag = (ImageView)parentView.findViewById(R.id.iv_flag);vh.setImg_flag(iv_flag);TextView tv = (TextView) parentView.findViewById(R.id.tv_typename);vh.setTitle(tv);ImageButton btn_dele = (ImageButton) parentView.findViewById(R.id.iv_dele);vh.setBtn_dele(btn_dele);ImageButton btn_add = (ImageButton) parentView.findViewById(R.id.iv_add);vh.setBtn_add(btn_add);return parentView;}

其实ViewHolder并不是什么神奇的工具,他只是一个简单的vo,保存着父一级view上个控件的应用,方便在重用时,加载新的内容而已。

class ViewHolder {    private TextView title;      private ImageView img_flag;    private ImageButton btn_add;    private ImageButton btn_dele;    public TextView getTitle() {return title;}public void setTitle(TextView title) {this.title = title;}public ImageView getImg_flag() {return img_flag;}public void setImg_flag(ImageView img_flag) {this.img_flag = img_flag;}public ImageButton getBtn_add() {return btn_add;}public void setBtn_add(ImageButton btn_add) {this.btn_add = btn_add;}public ImageButton getBtn_dele() {return btn_dele;}public void setBtn_dele(ImageButton btn_dele) {this.btn_dele = btn_dele;}}   

更多相关文章

  1. [android] Proguard代码混淆器如何排除指定的类或子类
  2. 【android】使用Event Bus模式解耦Android(安卓)App组件间通信
  3. 阿里云消息队列MQTT踩坑之路(阿里云MQTT Android客户端)
  4. Android(安卓)开发艺术探究V第三章之view的事件分发机制
  5. 菜鸟进阶之Android(安卓)Touch事件传递(一)
  6. Android应用《撕开美女衣服》的实现过程及源代码
  7. 4.2以上版本的sdk使用webview js和java代码交互必须加注解才能生
  8. android通过指定目录获取该目录下所有类(反编译)
  9. Android字符串进阶之一(特殊字符的输入)

随机推荐

  1. Android Error:Could not open cp_proj re
  2. Android 8.0 app内覆盖安装
  3. Android设置或清除默认桌面
  4. Android Studio 第七十七期 - Android 广
  5. andoird HTTP 工具类
  6. [Android]自定义系统菜单的背景
  7. 在android中获取系统后台运行的进程
  8. Android之View的视图测量过程
  9. android友盟注意事项
  10. android快捷方式的创建与删除