zoukankan      html  css  js  c++  java
  • Android基本控件之ListView(二)<ListView优化>

    之前我们说到ListView的基本用法。但是,有很多的时候会额外的占用一些内存,从而消耗了性能。既然有消耗性能的可能,那么我们就对其做出相应的优化

      我们首先来说说优化的步骤

        第一步将宽和高设置为填充父窗体,有助于填充item时,避免重复渲染ListView,而导致重复多次调用ListView

        第二步判断getView()方法中的convertView是否为空,如果为空就创建View,不为空就重复使用View

        第三步创建类ViewHolder来解决每次重复查找convertView中的组件

      然后,我们就来详细的说一说具体应该如何去优化

        我们首先创建一个内部类叫做ViewHolder,并在类中维护在item中的各种控件

        然后,我们在getView()方法中去维护一个ViewHolder。    

        然后,我们需要加上一个判断,去判断convertView是否为空,如果为空就证明屏幕显示的还是之前的并没有新的item进入到屏幕中

        那么,我们需要在其中给convertView赋值(通过布局填充器去实例化)

        然后,我们实例化一个ViewHolder

        然后,我们需要调用一个setTag()方法把ViewHolder放入到convertView中

        如果convertView不为空,就证明屏幕上显示的item有更新,那么我们就设置item中各个控件要显示的数据

        在此之前,我们需要通过getTag()方法convertView中获取到Viewholder

        最后返回convertView

      优化的过程就是这样。接下来,我们来使用上次的代码再实现一下优化

      我们还是来顺一下思路

       布局文件:

        我们需要每个item的布局(一个图标<ImageView>, 一个标题<TextView>,一个内容<TextView>),和主界面布局<ListView>

       Activity中:

        首先,按照套路,获取控件设置数据源设置适配器设置点击事件

        然后我们自定义适配器继承BaseAdapter,并实现其中的方法

        在getView方法中先判断convertView是否为空,如果为空就创建一个,如果不为空就设置值

        然后,我们定义一个类叫做ViewHodler,并在其中维护item布局中的各种控件

    接下来,我们按照我们所想的,来做一个具体的实现

      我们先来看item的布局

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="10dp">
        <ImageView
            android:id="@+id/iv_icon"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="5dp"
            android:src="@mipmap/ic_launcher"/>
        <TextView
            android:id="@+id/tv_title"
            android:layout_marginTop="10dp"
            android:layout_toRightOf="@+id/iv_icon"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="这是标题"
            android:textSize="20sp"/>
        <TextView
            android:id="@+id/tv_content"
            android:layout_toRightOf="@+id/iv_icon"
            android:layout_below="@+id/tv_title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:text="这是内容"/>
    </RelativeLayout>

    接下来,我们来看主界面布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main"
        android:layout_width="match_parent" android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context="application.smile.listview.MainActivity">
    
        <ListView
            android:id="@+id/listView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </RelativeLayout>

    现在,我们的布局文件就准备好了

    接下来,我们来看Activity中的状态

      我们先准备数据源

        //存储文字的数组
        private String [] names ={"郭嘉", "黄月英", "华佗", "刘备", "陆逊", "吕布", "吕蒙", "马超", "司马懿", "孙权",
                    "孙尚香", "夏侯惇", "许褚", "杨修", "张飞", "赵云", "甄姬", "周瑜", "诸葛亮"};
            //存储图片的数组
        private int [] images = {R.mipmap.guojia, R.mipmap.huangyueying, R.mipmap.huatuo, R.mipmap.liubei, R.mipmap.luxun, R.mipmap.lvbu, R.mipmap.lvmeng,
                    R.mipmap.machao, R.mipmap.simayi, R.mipmap.sunquan, R.mipmap.sunshangxiang, R.mipmap.xiahoudun, R.mipmap.xuchu, R.mipmap.yangxiu,
                    R.mipmap.zhangfei, R.mipmap.zhaoyun, R.mipmap.zhenji, R.mipmap.zhouyu, R.mipmap.zhugeliang};

      然后,我们找到控件

         //找到控件
            ListView listView  = (ListView) findViewById(R.id.listView);

       然后,我们设置适配器

      //设置适配器
            listView.setAdapter(new MyAdapter(this));

      这里看到了一个MyAdapter,我们一会再说

      接下来,我们设置点击事件

     //设置点击事件
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    //弹出吐司
                    Toast.makeText(MainActivity.this, "点我了?我是" + names[position], Toast.LENGTH_SHORT).show();
                }
            });

      接下来,我们来看自定义适配器

        该自定义适配器继承了BaseAdapter,并实现其中的4种方法

        在重写四种方法之前,我们先维护一个上下文和一个布局填充器,并为其提供一个构造方法去获得一个布局适配器。

     //维护一个上下文,为了得到布局填充器
            private Context context;
            //维护一个布局填充器,为了得到每个item 的布局
            private LayoutInflater layoutInflater;
    
            public MyAdapter(Context context) {
                //通过构造方法获取布局填充器对象
                layoutInflater = LayoutInflater.from(context);
            }

      然后,我们来重写那四个方法

      1.getCount

    //该方法是总共有多少个item
            @Override
            public int getCount() {
                return names.length;
            }

      2.getItem

      //该方法是得到每个item的值
            @Override
            public Object getItem(int position) {
                return names[position];
            }

      3.getItemId

       //该方法是得到每个item的id
            @Override
            public long getItemId(int position) {
                return position;
            }

      4.getView

     //该方法是获得视图,也是这些里面最重要的方法
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                ViewHolder viewHolder;
                if (convertView == null) {
                    //首先,我们通过布局填充器获得item的布局
                    convertView = layoutInflater.inflate(R.layout.item_layout, null);
                    //实例化ViewHodler
                    viewHolder = new ViewHolder();
                    //根据item的布局找到图片
                    viewHolder.iv_icon = (ImageView) convertView.findViewById(iv_icon);
                    //根据item的布局找到标题
                    viewHolder.tv_title = (TextView) convertView.findViewById(tv_title);
                    //根据item的布局找到内容
                    viewHolder.tv_content = (TextView) convertView.findViewById(tv_content);
                    //设置tag标记
                    convertView.setTag(viewHolder);
                }
                viewHolder = (ViewHolder) convertView.getTag();
                //设置图片源(也就是我们装图片的那个数组)
                viewHolder.iv_icon.setImageResource(images[position]);
                //设置标题文字
                viewHolder.tv_title.setText(names[position]);
                //设置内容文字
                viewHolder.tv_content.setText("我是" + names[position]);
                //返回item的布局
                return convertView;
            }

      然后,我们来定义一个内部类,叫做ViewHolder

     class ViewHolder {
                ImageView iv_icon;
                TextView tv_title;
                TextView tv_content;
            }

      我们来简单的整理一个思路

        首先,我们定义一个内部类叫做ViewHolder

        然后,我们在getView方法中去判断convertView是否为空,如果为空,就通过布局填充器把每个item的布局添加到convertView中。

        如果不为空就重复的利用这个布局,并在其中设置数据。

        最后,返回convertView

      这样,我们的ListView的优化就完成了。

      源码奉上:

    public class MainActivity extends AppCompatActivity {
        //存储文字的数组
        private String[] names = {"郭嘉", "黄月英", "华佗", "刘备", "陆逊", "吕布", "吕蒙", "马超", "司马懿", "孙权",
                "孙尚香", "夏侯惇", "许褚", "杨修", "张飞", "赵云", "甄姬", "周瑜", "诸葛亮"};
        //存储图片的数组
        private int[] images = {R.mipmap.guojia, R.mipmap.huangyueying, R.mipmap.huatuo, R.mipmap.liubei, R.mipmap.luxun, R.mipmap.lvbu, R.mipmap.lvmeng,
                R.mipmap.machao, R.mipmap.simayi, R.mipmap.sunquan, R.mipmap.sunshangxiang, R.mipmap.xiahoudun, R.mipmap.xuchu, R.mipmap.yangxiu,
                R.mipmap.zhangfei, R.mipmap.zhaoyun, R.mipmap.zhenji, R.mipmap.zhouyu, R.mipmap.zhugeliang};
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            //找到控件
            ListView listView = (ListView) findViewById(R.id.listView);
            //设置适配器
            listView.setAdapter(new MyAdapter(this));
            //设置点击事件
            listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    //弹出吐司
                    Toast.makeText(MainActivity.this, "点我了?我是" + names[position], Toast.LENGTH_SHORT).show();
                }
            });
        }
    
        /**
         * 自定义适配器,继承BaseAdapter
         */
        class MyAdapter extends BaseAdapter {
            //维护一个上下文,为了得到布局填充器
            private Context context;
            //维护一个布局填充器,为了得到每个item 的布局
            private LayoutInflater layoutInflater;
    
            public MyAdapter(Context context) {
                //通过构造方法获取布局填充器对象
                layoutInflater = LayoutInflater.from(context);
            }
    
            //该方法是总共有多少个item
            @Override
            public int getCount() {
                return names.length;
            }
    
            //该方法是得到每个item的值
            @Override
            public Object getItem(int position) {
                return names[position];
            }
    
            //该方法是得到每个item的id
            @Override
            public long getItemId(int position) {
                return position;
            }
    
            //该方法是获得视图,也是这些里面最重要的方法
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                ViewHolder viewHolder;
                if (convertView == null) {
                    //首先,我们通过布局填充器获得item的布局
                    convertView = layoutInflater.inflate(R.layout.item_layout, null);
                    //实例化ViewHodler
                    viewHolder = new ViewHolder();
                    //根据item的布局找到图片
                    viewHolder.iv_icon = (ImageView) convertView.findViewById(iv_icon);
                    //根据item的布局找到标题
                    viewHolder.tv_title = (TextView) convertView.findViewById(tv_title);
                    //根据item的布局找到内容
                    viewHolder.tv_content = (TextView) convertView.findViewById(tv_content);
                    //设置tag标记
                    convertView.setTag(viewHolder);
                }
                viewHolder = (ViewHolder) convertView.getTag();
                //设置图片源(也就是我们装图片的那个数组)
                viewHolder.iv_icon.setImageResource(images[position]);
                //设置标题文字
                viewHolder.tv_title.setText(names[position]);
                //设置内容文字
                viewHolder.tv_content.setText("我是" + names[position]);
                //返回item的布局
                return convertView;
            }
    
            class ViewHolder {
                ImageView iv_icon;
                TextView tv_title;
                TextView tv_content;
            }
        }
    }

    让程序写入生命,将代码融入灵魂

                        -------smile、zj

  • 相关阅读:
    BZOJ3631 [JLOI2014] 松鼠的新家
    HDU
    HDU
    HDU
    二分图求最大独立集模板
    HDU
    HDU
    HDU
    Codeforces 1197F Coloring Game 矩阵快速幂 (看题解)
    HDU
  • 原文地址:https://www.cnblogs.com/smilezj/p/6143543.html
Copyright © 2011-2022 走看看