listview控件的使用,listview控件的优化

来源:互联网 发布:最新php视频 编辑:程序博客网 时间:2024/06/10 04:42

参照网址:http://www.cnblogs.com/li1010425/p/6101468.html

ListView展示数据的原理

   在Android中,其实ListView就相当于web中的jsp,Adapter是适配器,它就相当于web中的Servlet,

   适配器的作用

    Adapter的作用就是把数据展示在Listview中

使用ListView的奇怪问题?

       在使用ListView的时候,如果把ListView的高设置为wrap_content,它会反复读取多次数据,然后在ListView中把数据显示出来,效率非常低,,这时候我们应该把ListView的高设置为match_parent,这样就能很好的解决读取多次再显示数据的问题了,因为ListView的高写成wrap_content,那么它的高不确定的,需要做多次的校验,确认数据是否能完全显示出来。

  下面我们通过案例说明这个问题

  

  当ListViewf控件的高度设置为wrap_content时,就会出现以下问题,如下图:

 

          

 

               图1                              图2

  我们可以看到手机屏幕图1中最多能够显示31条数据,但是图2中很明显看到当加载完31条记录时,紧接着又从0开始加载这31条记录,其实后面还加载了好几次,在这里就不一一截图出来了,那么如何解决呢?其实只需要修改一下ListView控件的高就可以了,把ListView控件中的高设置为match_parent

  

   但是还要注意一点,当是引入布局的时候,我们也需要设置它的父元素的高为match_parent

  

  也就是说,父元素和引入布局的ListView都需要设置为match_parent

    

  ListView控件的父子关系关系也是一样

  

  

   解决了读取多次数据问题后,我们来看看以下代码,然后运行看看结果是怎样的?

复制代码
 1 import android.app.Activity; 2 import android.os.Bundle; 3 import android.view.View; 4 import android.view.ViewGroup; 5 import android.widget.BaseAdapter; 6 import android.widget.ListView; 7 import android.widget.TextView; 8  9 10 public class MainActivity extends Activity {11 12     @Override13     protected void onCreate(Bundle savedInstanceState) {14         super.onCreate(savedInstanceState);15         setContentView(R.layout.weixin);16         17         //获取所需控件18         ListView ll = (ListView) findViewById(R.id.listView1);19       20         //使用适配器21         ll.setAdapter(new MyAdapter());22      23     }24     25    //定义一个适配器26     private class MyAdapter extends BaseAdapter{27         28         //返回条目数29         @Override30         public int getCount() {31             return 10000;32         }33 34         @Override35         public Object getItem(int position) {36             37             return null;38         }39 40         @Override41         public long getItemId(int position) {42             43             return 0;44         }45         46         /**47          * 获取一个view,用来显示listView的数据,会作为listView的一个条目显示48          * 49          * position       : 对应getCount()返回的索引50          * convertView : 缓存数据的对象51          */52         @Override53         public View getView(int position, View convertView, ViewGroup parent) {54             55            /**56              * 如果convertView是null,那么说明没有缓存,那么我们就创建TextView对象57              */58             TextView tv = tv = new TextView(MainActivity.this);59                 System.out.println("创建新的View"+position);60             62             tv.setText("呵呵"+position);63             return tv;64         }65         66     }67 }                     
复制代码

 

  运行结果:

     

  我们从结果可以看到,每次都是创建了一个新的对象,这样效率非常低,那么我们下面进行ListView的优化

 

ListView的优化策略

   

复制代码
 1 package com.example.uicustomviews; 2  3 import android.app.Activity; 4 import android.os.Bundle; 5 import android.view.View; 6 import android.view.ViewGroup; 7 import android.widget.BaseAdapter; 8 import android.widget.ListView; 9 import android.widget.TextView;10 11 12 public class MainActivity extends Activity {13 14     @Override15     protected void onCreate(Bundle savedInstanceState) {16         super.onCreate(savedInstanceState);17         setContentView(R.layout.weixin);18         19         //获取所需控件20         ListView ll = (ListView) findViewById(R.id.listView1);21       22         //使用适配器23         ll.setAdapter(new MyAdapter());24      25     }26     27    //定义一个适配器28     private class MyAdapter extends BaseAdapter{29         30         //返回条目数31         @Override32         public int getCount() {33             return 10000;34         }35 36         @Override37         public Object getItem(int position) {38             39             return null;40         }41 42         @Override43         public long getItemId(int position) {44             45             return 0;46         }47         48         /**49          * 获取一个view,用来显示listView的数据,会作为listView的一个条目显示50          * 51          * position       : 对应getCount()返回的索引52          * convertView : 缓存数据的对象53          */54         @Override55         public View getView(int position, View convertView, ViewGroup parent) {56             57             TextView tv = null;58             59             /**60              * 如果convertView是null,那么说明没有缓存,那么我们就创建TextView对象61              */62             if(convertView==null){63                 System.out.println("创建新的View"+position);64                 tv = new TextView(MainActivity.this);65             }else{66                 /**67                  * 否则就是有缓存,为了提高效率,那么我们就使用缓存中对象,不需要再次new了68                  */69                 tv = (TextView) convertView ;70                 System.out.println("使用缓存的View"+position);71             }72             73             tv.setText("呵呵"+position);74             return tv;75         }76         77     }78 }
复制代码

  运行结果如下图:  

      

  显然提高了效率,不再创建新的View,而是使用了缓存中的View

 

 

  下面我们把一个布局文件转为一个View(ListView中的一个条目)

复制代码
  1 package com.example.uicustomviews;  2   3 import android.app.Activity;  4 import android.os.Bundle;  5 import android.view.LayoutInflater;  6 import android.view.View;  7 import android.view.ViewGroup;  8 import android.widget.BaseAdapter;  9 import android.widget.ListView; 10  11  12  13 public class MainActivity extends Activity { 14  15     @Override 16     protected void onCreate(Bundle savedInstanceState) { 17         super.onCreate(savedInstanceState); 18         setContentView(R.layout.weixin); 19           20         //获取所需控件 21         ListView ll = (ListView) findViewById(R.id.listView1); 22        23         //使用适配器 24         ll.setAdapter(new MyAdapter()); 25       26     } 27      28    //定义一个适配器 29     private class MyAdapter extends BaseAdapter{ 30          31         //返回条目数 32         @Override 33         public int getCount() { 34             return 10000; 35         } 36  37         @Override 38         public Object getItem(int position) { 39              40             return null; 41         } 42  43         @Override 44         public long getItemId(int position) { 45              46             return 0; 47         } 48          49         /** 50          * 获取一个view,用来显示listView的数据,会作为listView的一个条目显示 51          *  52          * position       : 对应getCount()返回的索引 53          * convertView : 缓存数据的对象 54          */ 55         @Override 56         public View getView(int position, View convertView, ViewGroup parent) { 57              58             /** 59              * 可以插入广告 60              */ 61              62             View view = null; 63              64             /** 65              * 如果convertView是null,那么说明没有缓存,那么我们就创建TextView对象 66              */ 67             if(convertView==null){ 68                 //System.out.println("创建新的View"+position); 69                 //创建一个新的View对象,可以通过打气筒把一个布局资源转换成一个View对象 70                 //resource就是我们定义好的布局文件 71                 //方式一 72                 //view = View.inflate(MainActivity.this, R.layout.weixin_item, null); 73                  74                 //方式二 75                 //view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.weixin_item, null); 76                  77                 //方式三 78                 LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE); 79                  80                 view = inflater.inflate(R.layout.weixin_item, null); 81             }else{ 82                 /** 83                  * 否则就是有缓存,为了提高效率,那么我们就使用缓存中对象,不需要再次new了 84                  */ 85                 view = convertView ; 86                 //System.out.println("使用缓存的View"+position); 87             } 88              90             return view; 91         } 92          93     } 94 }
复制代码补充:

优化方式二:

  • ViewHolder的使用

  第一种优化方式有个缺点,就是每次在findviewById,重新找到控件,然后对控件进行赋值,这样会减慢加载的速度,其实我们可以创建一个内部类ViewHolder,里面的成员变量和view中所包含的组件个数、类型相同,在convertview为null的时候,把findviewbyId找到的控件赋给ViewHolder中对应的变量,就相当于先把它们装进一个容器,下次要用的时候,直接从容器中获取,这样是不是比findviewbyId效率要高一点?

需要用到两个方法:setTaggetTag方法:

优化方式三:


  • 使用分段加载 

   有些情况下我们需要加载网络中的数据,显示到ListView,而往往此时都是数据量比较多的一种情况,如果数据有1000条,没有优化过的ListView都是会一次性把数据全部加载出来的,很显然需要一段时间才能加载出来,我们不可能让用户面对着空白的屏幕等好几分钟,那么这时我们可以使用分段加载,比如先设置每次加载数据10条,当用户滑动ListView到底部的时候,我们再加载20条数据出来,然后使用Adapter刷新ListView,这样用户只需要等待10条数据的加载时间,这样也可以缓解一次性加载大量数据而导致OOM崩溃的情况。

优化方式四:


  • 使用分页加载 

  上面第三种方式其实也不能完全解决OOM崩溃的情况,因为虽然我们在分段中一次只增加10条数据到List集合中,然后再刷新到ListView中去,假如有10万条数据,如果我们顺利读到最后这个List集合中还是会累积海量条数的数据,还是可能会造成OOM崩溃的情况,这时候我们就需要用到分页,比如说我们将这10万条数据分为1000页,每一页100条数据,每一页加载时都覆盖掉上一页中List集合中的内容,然后每一页内再使用分批加载,这样用户的体验就会相对好一些。