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中的控件设置数据

  • 相关阅读:
    牛客练习赛51 D题
    Educational Codeforces Round 72 (Rated for Div. 2) C题
    Codeforces Round #583 (Div. 1 + Div. 2, based on Olympiad of Metropolises) C题
    Codeforces Round #583 (Div. 1 + Div. 2, based on Olympiad of Metropolises) A题
    Codeforces Round #583 (Div. 1 + Div. 2, based on Olympiad of Metropolises) A题
    Educational Codeforces Round 72 (Rated for Div. 2) B题
    Educational Codeforces Round 72 (Rated for Div. 2) A题
    《DSP using MATLAB》Problem 7.2
    《DSP using MATLAB》Problem 7.1
    《DSP using MATLAB》Problem 6.24
  • 原文地址:https://www.cnblogs.com/xs104/p/4796423.html
Copyright © 2011-2022 走看看