zoukankan      html  css  js  c++  java
  • Android笔记(二十五) ListView的缓存机制与BaseAdapter

           之前接触了ListView和Adapter,Adapter将数据源和View连接起来,实际应用中,我们要显示的数据往往有很多,而屏幕只有那么大,系统只能屏幕所能显示的内容,当我们滑动屏幕,会将旧的内容放入到缓冲池中,再从缓存池中拿出新的内容显示出来,这就是ListView的缓存机制,这一机制可以极大的节省系统资源。

    BaseAdapter

           BaseAdapter通常用于被扩展,扩展BaseAdapter可以对各项列表进行最大限度的定制。

           我们可以用自己的类去继承BaseAdapter,然后实现getCount()、getItem()、getItemId()、getView()这四个方法,来完成对Adapter的定制。

           getCount()    该方法返回ListView需要显示的数据量

           getItem()      该方法返回指定索引(position)所对应的数据项

           getItemId()  该方法返回对应的索引

           getView()      该方法返回每一项所显示的内容

    简单示例:

    package cn.lixyz.baseadaptertest;
    
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.View;
    import android.widget.AdapterView;
    import android.widget.ListView;
    import android.widget.Toast;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class MainActivity extends AppCompatActivity {
    
        List<ItemBean> itemBeanList;
        ListView listView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            itemBeanList = new ArrayList<ItemBean>();
            for (int i = 0; i < 20; i++) {
                ItemBean ib = new ItemBean(R.drawable.icon, "标题" + i, "内容" + i);
                itemBeanList.add(ib);
            }
    
            listView = (ListView) findViewById(R.id.listView);
            listView.setAdapter(new MyAdapter(this, itemBeanList));
    
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    Toast.makeText(MainActivity.this, "你选择的是:" + position, Toast.LENGTH_SHORT).show();
                }
            });
    
        }
    }
    MainActivity.java
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">
    
    
        <ListView
            android:id="@+id/listView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
    </LinearLayout>
    layout_main.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"
        android:orientation="vertical">
    
        <ImageView
            android:id="@+id/iv_icon"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:layout_marginLeft="10dp"
            android:layout_marginTop="10dp"
            android:src="@drawable/icon" />
    
        <TextView
            android:id="@+id/tv_name"
            android:layout_width="match_parent"
            android:layout_height="35dp"
            android:layout_marginTop="10dp"
            android:layout_toEndOf="@+id/iv_icon"
            android:gravity="center"
            android:text="标题"
            android:textSize="25dp" />
    
        <TextView
            android:id="@+id/tv_desc"
            android:layout_width="match_parent"
            android:layout_height="25dp"
            android:layout_below="@+id/tv_name"
            android:layout_marginLeft="10dp"
            android:layout_toEndOf="@+id/iv_icon"
            android:gravity="center"
            android:text="内容内容内容内容" />
    
    </RelativeLayout>
    layout_item.xml
    package cn.lixyz.baseadaptertest;
    
    /**
     * Created by LGB on 2015/9/9.
     */
    public class ItemBean {
        public int ItemImageResid;
        public String ItemName;
        public String Itemdesc;
    
        public ItemBean(int ItemImageResid, String ItemName, String Itemdesc) {
            this.ItemImageResid = ItemImageResid;
            this.ItemName = ItemName;
            this.Itemdesc = Itemdesc;
        }
    }
    ItemBean.java
    package cn.lixyz.baseadaptertest;
    
    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    import java.util.List;
    
    /**
     * Created by LGB on 2015/9/9.
     */
    public class MyAdapter extends BaseAdapter {
    
        private List<ItemBean> list;
        private LayoutInflater inflater;
    
        public MyAdapter(Context context, List<ItemBean> list) {
            this.list = list;
            inflater = LayoutInflater.from(context);
        }
    
        //该方法返回ListView需要显示的数据量
        @Override
        public int getCount() {
            return list.size();
        }
    
        //该方法返回指定索引(position)所对应的数据项
        @Override
        public Object getItem(int position) {
            return list.get(position);
        }
    
        //该方法返回对应的索引
        @Override
        public long getItemId(int position) {
            return 0;
        }
    
        //
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View view = inflater.inflate(R.layout.laytou_item, null);
            ImageView imageView = (ImageView) view.findViewById(R.id.iv_icon);
            TextView name = (TextView) view.findViewById(R.id.tv_name);
            TextView desc = (TextView) view.findViewById(R.id.tv_desc);
    
            imageView.setImageResource(list.get(position).ItemImageResid);
            name.setText(list.get(position).ItemName);
            desc.setText(list.get(position).Itemdesc);
    
            return view;
        }
    }
    MyAdapter.java

    运行结果:

     

           上面的代码中,我们可以看到一个ListView中的每一项都是我们直接使用Inflater新建并返回的,完全没有使用到ListView提供的缓存机制

    View view = inflater.inflate(R.layout.laytou_item, null);
    ......
    return view;

           有关inflater的内容,可以看这里:<转> Android LayoutInflater详解      Android 中LayoutInflater的使用

           我们稍对代码做一下修改:

    package cn.lixyz.baseadaptertest;
    
    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    import java.util.List;
    
    /**
     * Created by LGB on 2015/9/9.
     */
    public class MyAdapter extends BaseAdapter {
    
        private List<ItemBean> list;
        private LayoutInflater inflater;
    
        public MyAdapter(Context context, List<ItemBean> list) {
            this.list = list;
            inflater = LayoutInflater.from(context);
        }
    
        //该方法返回ListView需要显示的数据量
        @Override
        public int getCount() {
            return list.size();
        }
    
        //该方法返回指定索引(position)所对应的数据项
        @Override
        public Object getItem(int position) {
            return list.get(position);
        }
    
        //该方法返回对应的索引
        @Override
        public long getItemId(int position) {
            return 0;
        }
    
        //该方法返回每一项所显示的内容
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                convertView = inflater.inflate(R.layout.laytou_item, null);
            }
            ImageView imageView = (ImageView) convertView.findViewById(R.id.iv_icon);
            TextView name = (TextView) convertView.findViewById(R.id.tv_name);
            TextView desc = (TextView) convertView.findViewById(R.id.tv_desc);
    
            imageView.setImageResource(list.get(position).ItemImageResid);
            name.setText(list.get(position).ItemName);
            desc.setText(list.get(position).Itemdesc);
            return convertView;
        }
    }

           我们先判断要显示的view是否已经存在,如果不存在,才创建,如果存在,就直接返回,这样也就避免了多次重复创建。

             现在避免了多次创建View对象了,但是每次调用getView的时候,仍然会多次使用findViewById来创建组件,那么有没有办法可以避免在这个问题上面浪费资源呢,这里就使用到了view的getTag和setTag,通常我们会创建一个ViewHolder类然后实例化,然后通过setTag的方法将这个ViewHolder对象和View连接起来

             看代码:

    package cn.lixyz.baseadaptertest;
    
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.View;
    import android.widget.AdapterView;
    import android.widget.ListView;
    import android.widget.Toast;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class MainActivity extends AppCompatActivity {
    
        List<ItemBean> itemBeanList;
        ListView listView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            itemBeanList = new ArrayList<ItemBean>();
            for (int i = 0; i < 20; i++) {
                ItemBean ib = new ItemBean(R.drawable.icon, "标题" + i, "内容" + i);
                itemBeanList.add(ib);
            }
    
            listView = (ListView) findViewById(R.id.listView);
            listView.setAdapter(new MyAdapter(this, itemBeanList));
    
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    Toast.makeText(MainActivity.this, "你选择的是:" + position, Toast.LENGTH_SHORT).show();
                }
            });
    
        }
    }
    MainActivity.java
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">
    
    
        <ListView
            android:id="@+id/listView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
    </LinearLayout>
    activity_main.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"
        android:orientation="vertical">
    
        <ImageView
            android:id="@+id/iv_icon"
            android:layout_width="60dp"
            android:layout_height="60dp"
            android:layout_marginLeft="10dp"
            android:layout_marginTop="10dp" />
    
        <TextView
            android:id="@+id/tv_name"
            android:layout_width="match_parent"
            android:layout_height="35dp"
            android:layout_marginTop="10dp"
            android:layout_toEndOf="@+id/iv_icon"
            android:gravity="center"
            android:text="标题"
            android:textSize="25dp" />
    
        <TextView
            android:id="@+id/tv_desc"
            android:layout_width="match_parent"
            android:layout_height="25dp"
            android:layout_below="@+id/tv_name"
            android:layout_marginLeft="10dp"
            android:layout_toEndOf="@+id/iv_icon"
            android:gravity="center"
            android:text="内容内容内容内容" />
    
    </RelativeLayout>
    layout_item.xml
    package cn.lixyz.baseadaptertest;
    
    /**
     * Created by LGB on 2015/9/9.
     */
    public class ItemBean {
        public int ItemImageResid;
        public String ItemName;
        public String Itemdesc;
    
        public ItemBean(int ItemImageResid, String ItemName, String Itemdesc) {
            this.ItemImageResid = ItemImageResid;
            this.ItemName = ItemName;
            this.Itemdesc = Itemdesc;
        }
    }
    ItemBean.java
    package cn.lixyz.baseadaptertest;
    
    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    import java.util.List;
    
    /**
     * Created by LGB on 2015/9/9.
     */
    public class MyAdapter extends BaseAdapter {
    
        private List<ItemBean> list;
        private LayoutInflater inflater;
    
        public MyAdapter(Context context, List<ItemBean> list) {
            this.list = list;
            inflater = LayoutInflater.from(context);
        }
    
        //该方法返回ListView需要显示的数据量
        @Override
        public int getCount() {
            return list.size();
        }
    
        //该方法返回指定索引(position)所对应的数据项
        @Override
        public Object getItem(int position) {
            return list.get(position);
        }
    
        //该方法返回对应的索引
        @Override
        public long getItemId(int position) {
            return position;
        }
    
        //该方法返回每一项所显示的内容
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder vh = null;
            if (convertView == null) {
                vh = new ViewHolder();
                convertView = inflater.inflate(R.layout.laytou_item, null);
                vh.imageView = (ImageView) convertView.findViewById(R.id.iv_icon);
                vh.name = (TextView) convertView.findViewById(R.id.tv_name);
                vh.desc = (TextView) convertView.findViewById(R.id.tv_desc);
                convertView.setTag(vh);
            } else {
                vh = (ViewHolder) convertView.getTag();
            }
    
            vh.imageView.setImageResource(list.get(position).ItemImageResid);
            vh.name.setText(list.get(position).ItemName);
            vh.desc.setText(list.get(position).Itemdesc);
    
    
            return convertView;
        }
    
        //创建ViewHolder,避免重复的findViewById操作浪费资源
        class ViewHolder {
            public ImageView imageView;
            public TextView name;
            public TextView desc;
        }
    }
    MyAdapter.java

             运行结果是一样的

             在上面的代码中,我们创建了一个ViewHolder对象,用来保存一个Item的内容,然后使用setTag()将View和ViewHolder对象连接起来,假如convertView不为空的话,直接使用getTag来获取View对象,然后再给这个对象的属性赋值(也就是给Item的组件赋值),这样就充分利用了ListView的缓存机制,避免重复findViewById造成资源的浪费

             总结一下使用ListView缓存机制的思路

             1)创建Bean对象,用户封装数据ItemBean

             2)在构造方法中初始化用户映射的数据List

             3)创建ViewHolder类,创建布局映射关系

             4)判断convertView是否为空,如果为空,则创建,并设置tag,如果不为空,则通过getTag来去除ViewHolder

             5)给ViewHolder中的控件设置数据

  • 相关阅读:
    带有时间间隔的dp
    单调队列优化dp(捡垃圾的机器人)
    实现技巧
    树形dp(灯与街道)
    括号匹配(数组链表模拟)
    二分,求直线上覆盖所有点的最短时间
    可持久化链表(链式前向星)
    二分图匹配模板题
    网络流,设备、插头和转接器建图(简单map的应用)
    第七周助教总结
  • 原文地址:https://www.cnblogs.com/xs104/p/4796423.html
Copyright © 2011-2022 走看看