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

参照网址: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,那么它的高不确定的,需要做多次的校验,确认数据是否能完全显示出来。

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

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

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

 

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

 

               图1                              图2

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

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

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

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

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

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

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

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

  

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

listview控件的使用,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     @Override
13     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         @Override
30         public int getCount() {
31             return 10000;
32         }
33 
34         @Override
35         public Object getItem(int position) {
36             
37             return null;
38         }
39 
40         @Override
41         public long getItemId(int position) {
42             
43             return 0;
44         }
45         
46         /**
47          * 获取一个view,用来显示listView的数据,会作为listView的一个条目显示
48          * 
49          * position       : 对应getCount()返回的索引
50          * convertView : 缓存数据的对象
51          */
52         @Override
53         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控件的优化

 

  运行结果:

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

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

 

ListView的优化策略

   

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     @Override
15     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         @Override
32         public int getCount() {
33             return 10000;
34         }
35 
36         @Override
37         public Object getItem(int position) {
38             
39             return null;
40         }
41 
42         @Override
43         public long getItemId(int position) {
44             
45             return 0;
46         }
47         
48         /**
49          * 获取一个view,用来显示listView的数据,会作为listView的一个条目显示
50          * 
51          * position       : 对应getCount()返回的索引
52          * convertView : 缓存数据的对象
53          */
54         @Override
55         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 }
listview控件的使用,listview控件的优化

  运行结果如下图:  

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

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

 

 

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

listview控件的使用,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 }
listview控件的使用,listview控件的优化补充:

优化方式二:

  • 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集合中的内容,然后每一页内再使用分批加载,这样用户的体验就会相对好一些。