解决listview,gridview的getview多次调用有关问题

解决listview,gridview的getview多次调用问题
  • 在开发中我们经常会碰到一些奇葩的问题,但是我们还是得想办法去解决的呀,然后网上的解决方法确实比较多,但是我们还是得解决啊,然后我们肯定要先测试的。

    这2个控件的加载自定义的内容的时候,你要加载2次,但是当你打印的时候,却发现他运行的不止2次,getView和getCount中的log被疯狂调用,并且getVIew中的LOG每出来一次就是总数目条数,并且这总数目条数据的position的值都是0。一个GridView的getView竟然会被反复调用。尤其是当ItemView中需要加载图片时,很容易造成GC过多,很容易出现ANR,那时因为什么呢?

    2.- 非自定义的控件(原生的)
    这是android机制中要计算高的时候出现的一些多次调用,所以如果你不是自定义控件的话,那么你最好把这个控件的宽高属性改成:这连个属性给改为:android:layout_width=”fill_parent” android:layout_height=”fill_parent,最好它的父布局也设成这样好了。

  • 自定义控件(需要重写onmeasure和onlayout)
    这些控件是自定义的,往往他们的item的布局是复杂的,然后我们就需要动态的计算控件的高度了,然后布局放在哪个位置要就要去计算,如果随便弄一下还是可能会错位的。
    Google的解释,View在Draw的时候分成两个阶段:measure和layout,在measure阶段时主要就是为了计算两个参数:height和width。而且要注意的是,这是个递归的过程,从顶向下,DecorView开始依次调用自己子元素的measure。计算完成这两个参数后就开始layout,最后再是draw的调用。对于ListView,当然每一个Item都会被调用measure方法,而在这个过程中getView和getCount会被调用。
    然后我们显示界面一般都会用到baseAdapter,getView()的多次调用,所以我们对converview的复用就是非常关键的。(判断是否在onmeasure里,如果在,那么仅仅mInflater.inflate(R.layout.XXX),然后立刻返回这个convertView,如果不在onmeasure里,那么再去真正的onlayout)这里是参考[http://blog.csdn.net/ksr12333/article/details/18407527]的,非常感谢他的宝贵意见。
    因为listView没有暴露接口让我们知道onMesure()方法是否执行,所以我们只需加一个布尔值来进行判断:
    代码的实现就是:
    public boolean isMeasure;
                                     @Override
                                   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
                                           Log.d("onMeasure", "onMeasure");
                                            isMeasure = true;
                                            //计算itemView的宽高
                                          ......
                                      }
                             @Override
                           protected void onLayout(boolean changed, int l, int t, int r, int b) {
                               Log.d("onLayout", "onLayout");
                               isMeasure = false;
                               //设置layout
                                      ......
                                 }

         接下来就是我们对adapter的getView()方法的修改了:
        public View getView(int position, View convertView, ViewGroup parent) {  
                                ...  
                       //判断父控件的对象是不是你要展现的view对象
                        if(parent instanceof MyGridView){  
                              if(((MyGridView) parent).isMeasure()){  
                                     return convertView;  
                                  }  
                           }  
        ...  
          }  
  • 然后如果你是要实现里面的控件的点击事件的话,那就需要自己去事件分发了,把父控件不消费事件传给子控件就好了,然后子item里面可能有抢占焦点的控件,你可以在子控件setFocus=”false”
    或者父控件android:descendantFocusability=”afterDescendants”

  • 相信你应该知道怎么做了,这写也是参考别人的经验,我们要有拿来主义的精神,天朝的伸手党也是很多的,但是这也没有什么的,踩在别人的肩膀上没有什么不好,只要可以天天进步,学到你所想要