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

    xiaoxiao2021-03-25  98

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

    baseAdapter就诞生了。

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

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

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

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

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

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

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

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

    要实现的效果如下

    activity_main.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:layout_width="fill_parent"      android:layout_height="fill_parent"      android:orientation="vertical" >      <ListView           android:id="@+id/lv_listView"          android:layout_width="match_parent"          android:layout_height="match_parent"          ></ListView>    </LinearLayout>  

    item.xml

    <?xml version="1.0" encoding="utf-8"?>  <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:layout_width="match_parent"      android:layout_height="match_parent" >        <ImageView          android:id="@+id/iv_image"          android:layout_width="50dp"          android:layout_height="50dp"          android:layout_alignParentLeft="true"          android:src="@drawable/ic_launcher" />        <TextView          android:id="@+id/tv_nickName"          android:layout_width="fill_parent"          android:layout_height="wrap_content"          android:layout_toRightOf="@id/iv_image"          android:gravity="center_horizontal"          android:textSize="20sp"          android:text="昵称" />        <TextView          android:id="@+id/tv_content"          android:layout_width="fill_parent"          android:layout_height="wrap_content"          android:layout_toRightOf="@id/iv_image"          android:layout_below="@id/tv_nickName"          android:textSize="15sp"          android:text="内容" />    </RelativeLayout>  

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

    MyObject.class

    package com.example.baseadapter;    import android.widget.ImageView;  import android.widget.TextView;    public class MyObject {      private int imageViewId;      private String nickName;      private String content;        public MyObject(int imageViewId, String nickName, String content) {          this.imageViewId = imageViewId;          this.nickName = nickName;          this.content = content;      }        public String getNickName() {          return nickName;      }        public String getContent() {          return content;      }        public int getImageViewId() {          return imageViewId;      }    }  

    MainActivity.class

    package com.example.baseadapter;    import java.util.ArrayList;  import java.util.List;    import android.os.Bundle;  import android.app.Activity;  import android.view.Menu;  import android.widget.ListView;    public class MainActivity extends Activity {      private List<MyObject> list=new ArrayList<MyObject>();      private ListView listView;      private MyAdapter myAdapter;      @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_main);          listView=(ListView) findViewById(R.id.lv_listView);          for(int i=0;i<50;i++){              list.add(new MyObject(R.drawable.ic_launcher, "昵称"+i,   "内容"+i));          }          myAdapter=new MyAdapter(list, this);          listView.setAdapter(myAdapter);      }  }  

    自定义的adapter

    MyAdapter.class

    package com.example.baseadapter;    import java.util.List;    import android.content.Context;  import android.util.Log;  import android.view.View;  import android.view.ViewGroup;  import android.widget.BaseAdapter;  import android.widget.ImageView;  import android.widget.TextView;    public class MyAdapter extends BaseAdapter {        private long sum = 0;      private List<MyObject> list;      private Context context;        public MyAdapter(List<MyObject> list, Context context) {          this.list = list;          this.context = context;      }        @Override      public int getCount() {          // TODO Auto-generated method stub          return list.size();      }        @Override      public Object getItem(int position) {          // TODO Auto-generated method stub          return list.get(position);      }        @Override      public long getItemId(int position) {          // TODO Auto-generated method stub          return position;      }        @Override      public View getView(int position, View convertView, ViewGroup parent) {          // TODO Auto-generated method stub          // 逗比式           long star = System.nanoTime();           View view=View.inflate(context, R.layout.item, null);           ImageView imageView =(ImageView) view.findViewById(R.id.iv_image);           TextView nickName=(TextView) view.findViewById(R.id.tv_nickName);           TextView content=(TextView) view.findViewById(R.id.tv_content);           MyObject myObject=list.get(position);           imageView.setBackgroundResource(myObject.getImageViewId());           nickName.setText(myObject.getNickName());           content.setText(myObject.getContent());           long end = System.nanoTime();           sum += end - star;           Log.d("main", "逗比式" + sum);           return view;          // 普通式  //      long star = System.nanoTime();//获取系统纳秒时间  //      if (convertView == null) {  //          convertView = View.inflate(context, R.layout.item, null);  //      }  //      ImageView imageView = (ImageView) convertView  //              .findViewById(R.id.iv_image);  //      TextView nickName = (TextView) convertView  //              .findViewById(R.id.tv_nickName);  //      TextView content = (TextView) convertView.findViewById(R.id.tv_content);  //      MyObject myObject = list.get(position);  //      imageView.setBackgroundResource(myObject.getImageViewId());  //      nickName.setText(myObject.getNickName());  //      content.setText(myObject.getContent());  //      long end = System.nanoTime();  //      sum += end - star;  //      Log.d("main", "普通式" + sum);  //      return convertView;          // 文艺式          // long star = System.nanoTime();          // ViewHolder viewHolder;          // if (convertView == null) {          // viewHolder=new ViewHolder();          // convertView = View.inflate(context, R.layout.item, null);          // viewHolder.imageView = (ImageView) convertView          // .findViewById(R.id.iv_image);          // viewHolder.nickName = (TextView) convertView          // .findViewById(R.id.tv_nickName);          // viewHolder.content = (TextView) convertView          // .findViewById(R.id.tv_content);          // //通过setTag方式 使viewHolder和convertView绑定在一起          // convertView.setTag(viewHolder);          // }          // viewHolder=(ViewHolder) convertView.getTag();          // MyObject myObject = list.get(position);          // viewHolder.imageView.setBackgroundResource(myObject.getImageViewId());          // viewHolder.nickName.setText(myObject.getNickName());          // viewHolder.content.setText(myObject.getContent());          // long end = System.nanoTime();          // sum += end - star;          // Log.d("main", "文艺式"+sum);          // return convertView;      }        // 避免重复的findViewById      class ViewHolder {          public ImageView imageView;          private TextView nickName;          private TextView content;      }    }  

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

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

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

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

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

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

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

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

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

    class ViewHolder {      public ImageView imageView;      private TextView nickName;      private TextView content;  }  

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

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

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

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

     

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

    转载请注明原文地址: https://ju.6miu.com/read-23936.html

    最新回复(0)