ListView的优化

来源:互联网 发布:js append html字符串 编辑:程序博客网 时间:2024/05/16 15:08

一、复用convertView,减少findViewById>的次数 
优化一:复用Android系统本身为我们考虑了ListView的优化问题,在复写的Adapter的类中,比较重要的两个方法是getCount()和getView()。界面上有多少个条显示,就会调用多少次的getView()方法;因此如果在每次调用的时候,如果不进行优化,每次都会使用View.inflate(….)的方法,都要将xml文件解析,并显示到界面上,这是非常消耗资源的:因为有新的内容产生就会有旧的内容销毁,所以,可以复用旧的内容。


优化:
在getView()方法中,系统就为我们提供了一个复用view的历史缓存对象convertView,当显示第一屏的时候,每一个item都会新创建一个view对象,这些view都是可以被复用的;如果每次显示一个view都要创建一个,是非常耗费内存的;所以为了节约内存,可以在convertView不为null的时候,对其进行复用


2、优化二:缓存item条目的引用——ViewHolder
findViewById()这个方法是比较耗性能的操作,因为这个方法要找到指定的布局文件,进行不断地解析每个节点:从最顶端的节点进行一层一层的解析查询,找到后在一层一层的返回,如果在左边没找到,就会接着解析右边,并进行相应的查询,直到找到位置(如图)。因此可以对findViewById进行优化处理,需要注意的是:


特点:xml文件被解析的时候,只要被创建出来了,其孩子的id就不会改变了。根据这个特点,可以将孩子id存入到指定的集合中,每次就可以直接取出集合中对应的元素就可以了。


优化:
在创建view对象的时候,减少布局文件转化成view对象的次数;即在创建view对象的时候,把所有孩子全部找到,并把孩子的引用给存起来


优化方式


①定义存储控件引用的类ViewHolder


这里的ViewHolder类需要不需要定义成static,根据实际情况而定,如果item不是很多的话,可以使用,这样在初始化的时候,只加载一次,可以稍微得到一些优化
不过,如果item过多的话,建议不要使用。因为static是Java中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。所以用static修饰的变量,它的生命周期是很长的,如果用它来引用一些资源耗费过多的实例(比如Context的情况最多),这时就要尽量避免使用了。
②创建自定义的类:ViewHolder holder = null;③将子view添加到holder中:在创建新的listView的时候,创建新的ViewHolder,把所有孩子全部找到,并把孩子的引用给存起来通过view.setTag(holder)将引用设置到view中通过将孩子设置到此holder中,从而减少以后查询的次数.
④在复用listView中的条目的时候,通过view.getTag(),将view对象转化为holder,即转化成相应的引用,方便在下次使用的时候存入集合。通过view.getTag(holder)获取引用(需要强转)
下面给出实例
CallSmsSafeAdapter  adapter = new CallSmsSafeAdapter();
lv_callsms_safe.setAdapter(adapter);

适配器

private class CallSmsSafeAdapter extends BaseAdapter{@Overridepublic int getCount() {return infos.size();}@Overridepublic Object getItem(int position) {// TODO Auto-generated method stubreturn null;}@Overridepublic long getItemId(int position) {// TODO Auto-generated method stubreturn 0;}@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {View view;ViewHolder holder;if(convertView==null){view = View.inflate(getApplicationContext(), R.layout.list_item_callsms, null);holder = new ViewHolder();holder.tv_number=(TextView) view.findViewById(R.id.tv_black_number);holder.tv_mode=(TextView) view.findViewById(R.id.tv_block_mode);holder.iv_delete = (ImageView) view.findViewById(R.id.iv_delete);view.setTag(holder);}else{view=convertView;holder=(ViewHolder) view.getTag();//5%;}holder.tv_number.setText(infos.get(position).getNumber());return view;}}/** * view对象的容器 *记录孩子的内存地址。 *相当于一个记事本 */static class  ViewHolder{  //如果变量多就使用static ,视情况而定TextView tv_number;TextView tv_mode;ImageView iv_delete;}

二、ListView的其他优化:

1、尽量避免在BaseAdapter中使用static 来定义全局静态变量:

staticJava中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。所以用static修饰的变量,它的生命周期是很长的,如果用它来引用一些资源耗费过多的实例(比如Context的情况最多),这时就要尽量避免使用了。

2、尽量使用getApplicationContext

如果为了满足需求下必须使用Context的话:Context尽量使用Application Context,因为ApplicationContext的生命周期比较长,引用它不会出现内存泄露的问题

3、尽量避免在ListView适配器中使用线程:

因为线程产生内存泄露的主要原因在于线程生命周期的不可控制。如果自定义ListView中适配数据时使用AsyncTask自行开启线程的,这个比用Thread更危险,因为Thread只有在run函数不结束时才出现这种内存泄露问题,然而AsyncTask内部的实现机制是运用了线程执行池(ThreadPoolExcutor,这个类产生的Thread对象的生命周期是不确定的,是应用程序无法控制的,因此如果AsyncTask作为Activity的内部类,就更容易出现内存泄露的问题。解决办法如下:

①、将线程的内部类,改为静态内部类。

②、在线程内部采用弱引用保存Context引用





0 0