android:ListView缓存机制及BaseAdapter的三重境界(逗比式,普通式,文艺式)

来源:互联网 发布:成捷迅软件破解版 编辑:程序博客网 时间:2024/05/24 02:37

大家都知道listview的格式是一定的 而数据源确是多重多样的 这时候 就需要一种适配器来把数据源转换成listview要显示的格式

baseAdapter就诞生了。

listview和gridView的显示和缓存机制 如下图

大家都知道屏幕的大小是有限的 可是listview中的数据却可能很多 所以手机不能一下子展示所有的数据 它只会加载屏幕上显示的数据 。

如上图,当我们把屏幕往下滑动时 item1回收到recycler 而item8要显示在屏幕上 item8从recycler取出这样一个布局文件 并重新设置好item8要显示的数据 并设置要要显示的位置。总之一句话 需要才显示 显示完就被回收到缓存。

至于题目为何说BaseAdapter的三重境界(逗比式,普通式,文艺式) 区别在哪里那?就在如何运用listview的显示和缓存机制

在listview的适配器上 有这样一个方法

  1. @Override  
  2. public View getView(int position, View convertView, ViewGroup parent) {  
  3.     // TODO Auto-generated method stub  
  4.     return null;  
  5. }  


其中逗比式 普通式 文艺式的区别就在于如何使用这个方法

下面我们通过一个实例 来比较adapter的三重境界孰强孰弱

要实现的效果如下


activity_main.xml

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:layout_width="fill_parent"  
  3.     android:layout_height="fill_parent"  
  4.     android:orientation="vertical" >  
  5.     <ListView   
  6.         android:id="@+id/lv_listView"  
  7.         android:layout_width="match_parent"  
  8.         android:layout_height="match_parent"  
  9.         ></ListView>  
  10.   
  11. </LinearLayout>  


item.xml

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent" >  
  5.   
  6.     <ImageView  
  7.         android:id="@+id/iv_image"  
  8.         android:layout_width="50dp"  
  9.         android:layout_height="50dp"  
  10.         android:layout_alignParentLeft="true"  
  11.         android:src="@drawable/ic_launcher" />  
  12.   
  13.     <TextView  
  14.         android:id="@+id/tv_nickName"  
  15.         android:layout_width="fill_parent"  
  16.         android:layout_height="wrap_content"  
  17.         android:layout_toRightOf="@id/iv_image"  
  18.         android:gravity="center_horizontal"  
  19.         android:textSize="20sp"  
  20.         android:text="昵称" />  
  21.   
  22.     <TextView  
  23.         android:id="@+id/tv_content"  
  24.         android:layout_width="fill_parent"  
  25.         android:layout_height="wrap_content"  
  26.         android:layout_toRightOf="@id/iv_image"  
  27.         android:layout_below="@id/tv_nickName"  
  28.         android:textSize="15sp"  
  29.         android:text="内容" />  
  30.   
  31. </RelativeLayout>  


为了方便 ,我创建了一个myObject对象 用来封装item.xml要显示的数据

MyObject.class

  1. package com.example.baseadapter;  
  2.   
  3. import android.widget.ImageView;  
  4. import android.widget.TextView;  
  5.   
  6. public class MyObject {  
  7.     private int imageViewId;  
  8.     private String nickName;  
  9.     private String content;  
  10.   
  11.     public MyObject(int imageViewId, String nickName, String content) {  
  12.         this.imageViewId = imageViewId;  
  13.         this.nickName = nickName;  
  14.         this.content = content;  
  15.     }  
  16.   
  17.     public String getNickName() {  
  18.         return nickName;  
  19.     }  
  20.   
  21.     public String getContent() {  
  22.         return content;  
  23.     }  
  24.   
  25.     public int getImageViewId() {  
  26.         return imageViewId;  
  27.     }  
  28.   
  29. }  


MainActivity.class

  1. package com.example.baseadapter;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. import android.os.Bundle;  
  7. import android.app.Activity;  
  8. import android.view.Menu;  
  9. import android.widget.ListView;  
  10.   
  11. public class MainActivity extends Activity {  
  12.     private List<MyObject> list=new ArrayList<MyObject>();  
  13.     private ListView listView;  
  14.     private MyAdapter myAdapter;  
  15.     @Override  
  16.     protected void onCreate(Bundle savedInstanceState) {  
  17.         super.onCreate(savedInstanceState);  
  18.         setContentView(R.layout.activity_main);  
  19.         listView=(ListView) findViewById(R.id.lv_listView);  
  20.         for(int i=0;i<50;i++){  
  21.             list.add(new MyObject(R.drawable.ic_launcher, "昵称"+i,   "内容"+i));  
  22.         }  
  23.         myAdapter=new MyAdapter(list, this);  
  24.         listView.setAdapter(myAdapter);  
  25.     }  
  26. }  


自定义的adapter

MyAdapter.class

  1. package com.example.baseadapter;  
  2.   
  3. import java.util.List;  
  4.   
  5. import android.content.Context;  
  6. import android.util.Log;  
  7. import android.view.View;  
  8. import android.view.ViewGroup;  
  9. import android.widget.BaseAdapter;  
  10. import android.widget.ImageView;  
  11. import android.widget.TextView;  
  12.   
  13. public class MyAdapter extends BaseAdapter {  
  14.   
  15.     private long sum = 0;  
  16.     private List<MyObject> list;  
  17.     private Context context;  
  18.   
  19.     public MyAdapter(List<MyObject> list, Context context) {  
  20.         this.list = list;  
  21.         this.context = context;  
  22.     }  
  23.   
  24.     @Override  
  25.     public int getCount() {  
  26.         // TODO Auto-generated method stub  
  27.         return list.size();  
  28.     }  
  29.   
  30.     @Override  
  31.     public Object getItem(int position) {  
  32.         // TODO Auto-generated method stub  
  33.         return list.get(position);  
  34.     }  
  35.   
  36.     @Override  
  37.     public long getItemId(int position) {  
  38.         // TODO Auto-generated method stub  
  39.         return position;  
  40.     }  
  41.   
  42.     @Override  
  43.     public View getView(int position, View convertView, ViewGroup parent) {  
  44.         // TODO Auto-generated method stub  
  45.         // 逗比式  
  46.          long star = System.nanoTime();  
  47.          View view=View.inflate(context, R.layout.item, null);  
  48.          ImageView imageView =(ImageView) view.findViewById(R.id.iv_image);  
  49.          TextView nickName=(TextView) view.findViewById(R.id.tv_nickName);  
  50.          TextView content=(TextView) view.findViewById(R.id.tv_content);  
  51.          MyObject myObject=list.get(position);  
  52.          imageView.setBackgroundResource(myObject.getImageViewId());  
  53.          nickName.setText(myObject.getNickName());  
  54.          content.setText(myObject.getContent());  
  55.          long end = System.nanoTime();  
  56.          sum += end - star;  
  57.          Log.d("main", "逗比式" + sum);  
  58.          return view;  
  59.         // 普通式  
  60. //      long star = System.nanoTime();//获取系统纳秒时间  
  61. //      if (convertView == null) {  
  62. //          convertView = View.inflate(context, R.layout.item, null);  
  63. //      }  
  64. //      ImageView imageView = (ImageView) convertView  
  65. //              .findViewById(R.id.iv_image);  
  66. //      TextView nickName = (TextView) convertView  
  67. //              .findViewById(R.id.tv_nickName);  
  68. //      TextView content = (TextView) convertView.findViewById(R.id.tv_content);  
  69. //      MyObject myObject = list.get(position);  
  70. //      imageView.setBackgroundResource(myObject.getImageViewId());  
  71. //      nickName.setText(myObject.getNickName());  
  72. //      content.setText(myObject.getContent());  
  73. //      long end = System.nanoTime();  
  74. //      sum += end - star;  
  75. //      Log.d("main", "普通式" + sum);  
  76. //      return convertView;  
  77.         // 文艺式  
  78.         // long star = System.nanoTime();  
  79.         // ViewHolder viewHolder;  
  80.         // if (convertView == null) {  
  81.         // viewHolder=new ViewHolder();  
  82.         // convertView = View.inflate(context, R.layout.item, null);  
  83.         // viewHolder.imageView = (ImageView) convertView  
  84.         // .findViewById(R.id.iv_image);  
  85.         // viewHolder.nickName = (TextView) convertView  
  86.         // .findViewById(R.id.tv_nickName);  
  87.         // viewHolder.content = (TextView) convertView  
  88.         // .findViewById(R.id.tv_content);  
  89.         // //通过setTag方式 使viewHolder和convertView绑定在一起  
  90.         // convertView.setTag(viewHolder);  
  91.         // }  
  92.         // viewHolder=(ViewHolder) convertView.getTag();  
  93.         // MyObject myObject = list.get(position);  
  94.         // viewHolder.imageView.setBackgroundResource(myObject.getImageViewId());  
  95.         // viewHolder.nickName.setText(myObject.getNickName());  
  96.         // viewHolder.content.setText(myObject.getContent());  
  97.         // long end = System.nanoTime();  
  98.         // sum += end - star;  
  99.         // Log.d("main", "文艺式"+sum);  
  100.         // return convertView;  
  101.     }  
  102.   
  103.     // 避免重复的findViewById  
  104.     class ViewHolder {  
  105.         public ImageView imageView;  
  106.         private TextView nickName;  
  107.         private TextView content;  
  108.     }  
  109.   
  110. }  


BaseAdapter的三重境界(逗比式,普通式,文艺式)的代码已经在上面  

下面我们分析一下第一种为什么叫逗比式

前面已经说了,liseview具有缓存机制 可以将使用过的item放入缓冲池中,而在这里 每次调用getview方法的时候 我们都是创建新的view对象 并没有利用listview的缓存机制

没有任何处理 ,效率及其低下,所以我们称它为逗比式 

而第二种 普通式是利用了getview方法中传入的contentview对象 并且加一个if判断

  1. if (convertView == null) {  
  2.     convertView = View.inflate(context, R.layout.item, null);  
  3. }  

虽然只是一个if判断  但是 通过这个判断 可以避免创建大量的contentview对象 节省了大量的时间 利用了ListView的缓存特性 如果没有缓存才创建新的view 对getview方法进行了非常好的优化  但这仅仅只算入门,因为findViewById依然会浪费大量的时间 所以我们称这种方法为普通式

那么第三种境界 文艺式 就是对findViewById的优化了 把findViewById 也放入if判断语句中 就ok了

我们需要创建一个内部类 里面有三个成员变量 都是我们item.xml文件中的三个控件

  1. class ViewHolder {  
  2.     public ImageView imageView;  
  3.     private TextView nickName;  
  4.     private TextView content;  
  5. }  

通过viewHolder.setTag()方法 把viewHolder和contentView关联在一起 然后通过getTag方法得到viewHolder

这种方法不仅利用了listview的缓存,更通过viewHolder来实现显示视图的缓存,避免多次使用findViewById方法

作为一个有情怀的程序员 这才是最文艺的写法~

大家可能看到了我代码中输出的log日志 下面我附上结果 大家比较一下 这里listview中只有50条数据 全部是滑倒底部

 

至此BaseAdapter的三重境界(逗比式,普通式,文艺式)孰强孰弱 一目了然~(如果有出入 请你把listview中的数据设置多一些)

0 0
原创粉丝点击