• 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

  • 相关阅读:
    JAVA基础——编程练习(二)
    JAVA基础——面向对象三大特性:封装、继承、多态
    JVM内存
    50. Pow(x, n) (JAVA)
    47. Permutations II (JAVA)
    46. Permutations (JAVA)
    45. Jump Game II (JAVA)
    43. Multiply Strings (JAVA)
    42. Trapping Rain Water (JAVA)
    41. First Missing Positive (JAVA)
  • 原文地址:https://www.cnblogs.com/smilezj/p/6143543.html
Copyright © 2020-2023  润新知