• ListView加载性能优化---ViewHolder---分页


        ListView是Android中一个重要的组件,可以使用它加列表数据,用户可以自己定义列表数据,同时ListView的数据加载要借助Adapter,一般情况下要在Adapter类中重写getCount(),getItem(),getItemId(),getView()四个方法。自定义列表项,以及数据的加载在getView()中处理。当ListView加载的列表项数据过多时,会占用大量的内存,影响性能,因此要对ListView进行优化。

         getView的加载方法有3种形式,如下:

         1.每次创建一个view,然后加载数据,加载速度慢

            /**
             * 1.每次都创建一个View
             */
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                LayoutInflater inflater = LayoutInflater.from(context);
                View view = inflater.inflate(R.layout.listview_item_two,null);
                ImageView iv = (ImageView) view.findViewById(R.id.lv_listview_adapter_img);
                TextView tv = (TextView) view.findViewById(R.id.tv_listview_adapter_name);
                iv.setImageResource(icons[position]);
                tv.setText(titles[position]);
                return view;
            }
    

      2.当convertView不为空的时候直接重新使用convertView,为空时新建view,这样可以减少了很多不必要的View的创建,然后加载数据

           /**
             * 2.复用convertView,减少不必要的创建
             * 当convertView不为空的时候直接重新使用convertView从而减少了很多不必要的View的创建,然后加载数据
             * @param position
             * @param convertView
             * @param parent
             * @return
             */
           @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                if(convertView==null){
                    LayoutInflater inflater = LayoutInflater.from(context);
                    convertView = inflater.inflate(R.layout.listview_item_two,null);
                }
                ImageView iv = (ImageView) convertView.findViewById(R.id.lv_listview_adapter_img);
                TextView tv = (TextView) convertView.findViewById(R.id.tv_listview_adapter_name);
                iv.setImageResource(icons[position]);
                tv.setText(titles[position]);
                return convertView;
            }
    

      3.定义一个ViewHolder,将convetView的tag设置为ViewHolder,不为空时重新使用即可

      ViewHolder将需要缓存的view封装好,convertView的setTag才是将这些缓存起来供下次调用。 当你的listview里布局多样化的时候 viewholder的作用体现明显,效率再一次提高。 View的findViewById()方法也是比较耗时的,因此需要考虑只调用一次,之后就用View.getTag()方法来获得ViewHolder对象。

    当加载100条数据时,采用分页,每页加载20条,相当于创建了20个convertview。再加载21-40这二十条时,不需要重新创建20个convertview。第21条复用第1条的convertView,第22条复用第2条的convertView.......  

      @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                ViewHolder vh;
                if(convertView==null){
                    LayoutInflater inflater = LayoutInflater.from(context);
                    convertView = inflater.inflate(R.layout.listview_item_two,null);
                    vh = new ViewHolder();
                    vh.iv = (ImageView) convertView.findViewById(R.id.lv_listview_adapter_img);
                    vh.tv = (TextView) convertView.findViewById(R.id.tv_listview_adapter_name);
                    convertView.setTag(vh);
                }else{
                    vh = (ViewHolder)convertView.getTag();
                }
                vh.iv.setImageResource(icons[position]);
                vh.tv.setText(titles[position]);
                return convertView;
            }
            static class ViewHolder{
                ImageView iv;
                TextView tv;
            }
    

      以下是一个亲测的Demo案例,代码及运行结果如下:

         1.ListViewActivity.class 

    public class ListViewActivity extends AppCompatActivity {
    
        private ListView listView_five;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_list_view_adapter);
    
            listView_five = (ListView) findViewById(R.id.lv_listview_adater);
    
            listView_five.setAdapter(new MyAdapter(this));
            listView_five.setOnItemClickListener(new AdapterView.OnItemClickListener(){
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    Toast.makeText(ListViewActivity.this,"position="+position,Toast.LENGTH_LONG).show();
                }
            });
        }
    
        static class MyAdapter extends BaseAdapter{
            private String[] titles = {"title-1","title-2","title-3","title-4"};
            private int[] icons = {android.R.drawable.ic_lock_idle_alarm,android.R.drawable.ic_lock_idle_alarm,
                    android.R.drawable.ic_lock_idle_alarm,android.R.drawable.ic_lock_idle_alarm};
            private Context context;
            public MyAdapter(Context context){
                this.context = context;
            }
    
            @Override
            public int getCount() {
                return titles.length;
            }
    
            @Override
            public Object getItem(int position) {
                return titles[position];
            }
    
            @Override
            public long getItemId(int position) {
                return position;
            }
    
            /**
             * 1.每次都创建一个View
             */
            /*@Override
            public View getView(int position, View convertView, ViewGroup parent) {
                LayoutInflater inflater = LayoutInflater.from(context);
                View view = inflater.inflate(R.layout.listview_item_two,null);
                ImageView iv = (ImageView) view.findViewById(R.id.lv_listview_adapter_img);
                TextView tv = (TextView) view.findViewById(R.id.tv_listview_adapter_name);
                iv.setImageResource(icons[position]);
                tv.setText(titles[position]);
                return view;
            }*/
    
            /**
             * 2.复用convertView,减少不必要的创建
             * 当convertView不为空的时候直接重新使用convertView从而减少了很多不必要的View的创建,然后加载数据
             * @param position
             * @param convertView
             * @param parent
             * @return
             */
           /* @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                if(convertView==null){
                    LayoutInflater inflater = LayoutInflater.from(context);
                    convertView = inflater.inflate(R.layout.listview_item_two,null);
                }
                ImageView iv = (ImageView) convertView.findViewById(R.id.lv_listview_adapter_img);
                TextView tv = (TextView) convertView.findViewById(R.id.tv_listview_adapter_name);
                iv.setImageResource(icons[position]);
                tv.setText(titles[position]);
                return convertView;
            }*/
    
            /**
             * 3.定义一个ViewHolder,将convetView的tag设置为ViewHolder,不为空时重新使用即可
             * @param position
             * @param convertView
             * @param parent
             * @return
             */
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                ViewHolder vh;
                if(convertView==null){
                    LayoutInflater inflater = LayoutInflater.from(context);
                    convertView = inflater.inflate(R.layout.listview_item_two,null);
                    vh = new ViewHolder();
                    vh.iv = (ImageView) convertView.findViewById(R.id.lv_listview_adapter_img);
                    vh.tv = (TextView) convertView.findViewById(R.id.tv_listview_adapter_name);
                    convertView.setTag(vh);
                }else{
                    vh = (ViewHolder)convertView.getTag();
                }
                vh.iv.setImageResource(icons[position]);
                vh.tv.setText(titles[position]);
                return convertView;
            }
            static class ViewHolder{
                ImageView iv;
                TextView tv;
            }
        }
    }
    

      

    2.activity_list_view_adapter.xml

    <?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:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <ListView
            android:id="@+id/lv_listview_adater"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:dividerHeight="10dp"
            android:listSelector="#00ff00"
            android:scrollbars="vertical|horizontal"
            />
    </RelativeLayout>
    

      

    3.listview_item_two.xml

    <?xml version="1.0" encoding="utf-8"?>
    <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">
    
        <ImageView
            android:id="@+id/lv_listview_adapter_img"
            android:src="@mipmap/gradview_dog_one"
            android:layout_width="wrap_content"
            android:layout_gravity="center"
            android:layout_height="wrap_content" />
        <TextView
            android:id="@+id/tv_listview_adapter_name"
            android:text="拉布拉多"
            android:layout_gravity="center"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    
    </LinearLayout>
    

    三种方法的运行结果均相同,如下所示: 

     

    参考网址:http://blog.csdn.net/jacman/article/details/7087995

         http://blog.csdn.net/pkxiuluo01/article/details/7380874

    ListView分页的实现:

    1.PageActivity.class

    /**
     * ListView分页
     * 实现OnScrollListener监听
     */
    public class PageActivity extends AppCompatActivity implements AbsListView.OnScrollListener{
        private ListView listView_six;
        private int index = 1;
        private MyAdapter myAdapter;
        private Vector<News> news = new Vector<>();//线程安全的容器
        private static final int DATA_UPDATE = 0x1;//数据更新完成后的标记
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_page);
    
            listView_six = (ListView) findViewById(R.id.lv_listview_page);
            listView_six.setOnScrollListener(this);
            //引入加载缓冲布局,并添加到ListView的底部
            View footView = getLayoutInflater().inflate(R.layout.load_item,null);
            listView_six.addFooterView(footView);
            initData();
            myAdapter = new MyAdapter(this);
            listView_six.setAdapter(myAdapter);
        }
    
        //加载数据,每次加载10条
        private void initData() {
            for(int i = 0;i < 10;i++){
                News n = new News();
                n.setTitle("title"+index);
                n.setContent("content"+index);
                index++;
                news.add(n);
            }
        }
    
        private int visibleLastIndex;//用来可显示的最后一条数据的索引
        /**
         *
         * @param view
         * @param scrollState 滚动状态
         * SCROLL_STATE_IDLE:不再滚动时(停止)
         */
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            if(myAdapter.getCount() == visibleLastIndex && scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE){
                new loadDataThread().start();
            }
    
        }
    
        /**
         *
         * @param view
         * @param firstVisibleItem 第一次显示的
         * @param visibleItemCount 可显示的总量
         * @param totalItemCount
         */
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            visibleLastIndex = firstVisibleItem + visibleItemCount -1;
        }
    
        //线程之间通讯机制
        private Handler handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what){
                    case DATA_UPDATE:
                        //告知Adapter刷新数据
                        myAdapter.notifyDataSetChanged();
                        break;
                    default:
                        break;
                }
            }
        };
    
        //子线程通知UI线程
        class loadDataThread extends Thread{
            @Override
            public void run() {
                super.run();
                //前10条数据加载完成时,再加载另外10条
                initData();
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //通过Handler向主线程发送一个标记
                handler.sendEmptyMessage(DATA_UPDATE);
            }
        }
        //自定义Adapter
        class MyAdapter extends BaseAdapter{
            private Context context;
            public MyAdapter(Context context){
                this.context = context;
            }
            @Override
            public int getCount() {
                return news!=null?news.size():0;
            }
    
            @Override
            public Object getItem(int position) {
                return news.get(position);
            }
    
            @Override
            public long getItemId(int position) {
                return position;
            }
    
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                ViewHolder vh;
                if(convertView==null){
                    LayoutInflater inflater = LayoutInflater.from(context);
                    convertView = inflater.inflate(R.layout.listview_item_three,null);
                    vh = new ViewHolder();
                    vh.tv_one = (TextView) convertView.findViewById(R.id.tv_page_title);
                    vh.tv_two = (TextView) convertView.findViewById(R.id.tv_page_content);
                    convertView.setTag(vh);
                }else{
                    vh = (ViewHolder)convertView.getTag();
                }
    
                News n = news.get(position);
                vh.tv_one.setText(n.getTitle()+"---");
                vh.tv_two.setText(n.getContent());
                return convertView;
            }
            class ViewHolder{
                TextView tv_one;
                TextView tv_two;
            }
        }
    }
    

      2.activity_page.xml

    <?xml version="1.0" encoding="utf-8"?>
    <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"
        tools:context="com.langdon.taiyang.androidtest.listview.PageActivity">
    
        <ListView
            android:id="@+id/lv_listview_page"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:dividerHeight="10dp"
            android:listSelector="#00ff00"
            android:scrollbars="vertical|horizontal"
            />
    </LinearLayout>
    

      3.load_item.xml

    <?xml version="1.0" encoding="utf-8"?>
    <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"
        tools:context="com.langdon.taiyang.androidtest.listview.PageActivity">
    
        <ListView
            android:id="@+id/lv_listview_page"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:dividerHeight="10dp"
            android:listSelector="#00ff00"
            android:scrollbars="vertical|horizontal"
            />
    </LinearLayout>
    

      4.listview_item_three.xml

    <?xml version="1.0" encoding="utf-8"?>
    <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="horizontal">
    
        <TextView
            android:id="@+id/tv_page_title"
            android:text="标题"
            android:layout_gravity="center"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
        <TextView
            android:id="@+id/tv_page_content"
            android:text="内容"
            android:layout_gravity="center"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    
    </LinearLayout>
    

      运行效果如下:

  • 相关阅读:
    写了一个具有future接口的rust测试代码
    lua:写了个基于协程的task调度库
    最近阅读
    电视投屏
    树莓派 系统备份
    Kindle支持的文件格式
    树莓派 more
    用google translate大文件
    NFC 大电池 高性价比手机
    rust debug之基于pdb
  • 原文地址:https://www.cnblogs.com/langdon/p/6220993.html
Copyright © 2020-2023  润新知