关于ListView优化的一点心得

  最近在实现一个下载功能【多线程断点续传】的时候,发现在下载的时候某个listview(其实是expandablelistview,不过也差不多)会变得非常卡,注意是非常卡而不是一般安卓的卡顿。仔细研究了一通,进行了一系列比较低端的优化,纯粹当经验分享了~

  1、使用convertView,这个也是非常常见的方法,如果发现你网上参考来的代码(一般在adapter里的getView()方法中)没有这一段,那不妨加上~android的listview(包括expandablelistview,下同)是动态加载内容的,也就是说一般而言只会加载你的当前屏幕可以加载的最大列表项(例如列表项共有100条,但是你的屏幕只能同屏展示10条,那么系统也只会加载这10条的内容),然后离开当前屏幕的内容也会被回收,变成了“convertView”,假如你又返回刚刚的内容的话,就没必要重新加载了,直接使用convertView即可。

View view = convertView;
if (view == null) {
                LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                view = inflater.inflate(R.layout.member_childitem, null);    
            }

  2、尽量不在列表项中使用查询数据库的方法来决定展示什么内容。例如一个团购列表,每一条都有一个是否支持退票的参数,通过查询数据库获得。假如这个时候直接将搜索数据库的方法写进getView中,那么每次加载列表项——假设10条,就得从数据库里搜索10次结果。结合上一条所说的,假如你的getview里的数据不是固定的,那么系统自然不会生成convertView,这样一来对于一个列表你上下滑动的时候会出现比较明显的卡顿的现象,因为每一条都必须查询数据库,而且无法使用convertView。所以必须将数据写在getView()之外——也就是让getView()里面使用的数据是相对静态的,尤其是对数据库的查询不要写在getView之中。遇到必须通过数据库查询判断列表项的,可以在getView之前查询好数据用合适的数据结构保存起来,然后getView方法内只需要去查询该数据结构就好了。

  3、由2可以得知应该将列表项的数据查询统一放到getView外面进行,但是这样一来一旦刷新就意味着很多条列表项的信息都要一次过搜索出来,会形成比较明显的卡的现象。而这里数据库的查询效率问题就至关重要了。通常我们有两种查询方式

  第一种,直接查询单条数据:
  

    public int queryIfIsFavorite(int local_id){
        int r=2;
        SQLiteDatabase db = helper.getWritableDatabase();
        Cursor c=db.rawQuery("SELECT * FROM favoritemusic where local_id="+local_id,null);
        if(c.moveToNext()){
            r=1;
        }
        db.close();
        return r;
    }

  第二种,以列表为单位查询

public List<Integer> queryIfIsFavorite(List<MyMusic> list){
        SQLiteDatabase db = helper.getWritableDatabase();
        List<Integer> positions = new ArrayList<Integer>();
        for(int i=0;i<list.size();i++){
            Cursor c=db.rawQuery("SELECT * FROM favoritemusic where local_id="+list.get(i).getLocal_id(),null);
            if(c.moveToNext()){
                positions.add(1);
            }
            else{
                positions.add(2);
            }
        }
        db.close();
        return positions;
    }

  两种查询其实本质上是一样的,只是第二种查询将对列表的操作也写进db类里去了,相对第一种可重用性小很多,但是第二种方法和第一种相比最优秀的地方在于仅仅开关了一次SqliteDatabase——实际上对于数据库的操作而言,开关数据库远比一般的动作要消耗更多的资源,所以哪怕代码看上去没那么简洁美观,但有时为了提高效率还是不妨写多一个这样的方法的~

  另外,在不进行下载动作的时候,即使不进行上述代码改进,在现在的安卓手机配置下也不会有太严重的卡的问题,不过一旦进行下载。。。这也就意味着在进行下载操作的时候(暂时不确定与多线程下载有无关系,可能进行连续的读写操作也会)操作数据库将会造成非常大的消耗。

原文地址:https://www.cnblogs.com/blairsProgrammer/p/3560351.html