zoukankan      html  css  js  c++  java
  • BaseAdapter优化深入分析

    BaseAdapter是一个数据适配器,将我们提供的数据格式化为ListView可以显示的数据,BaseAdapter的优化直接影响到ListView的显示效率。
    我们都知道,ListView自带有回收机制,当一个Item滑出屏幕的时候,ListView会自动把这个ListView回收到缓冲区,当有一个Item滑入屏幕的时候,ListView会自动从缓冲区读取一个Item,并给它赋上值,然后显示出来,这便是ListView的回收机制,然而,如果你在BaseAdapter中没有做相应的优化,你的程序有可能根本就没有使用ListView的回收机制,这将会造成很大的资源浪费。好了,下来我们看看BaseAdater的优化问题。


    • 第一步:新建项目并且准备数据

      1.新建一个android项目,修改主布局文件:

    <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"
        tools:context="com.example.baseadapter.MainActivity" >
        <ListView 
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/listview"
            ></ListView>
    </RelativeLayout>

    2.在MainActivity中对数据进行初始化:

    public class MainActivity extends Activity {
    
        private ListView listView;
        private List<Person> list;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            listView = (ListView) this.findViewById(R.id.listview);
            initData();
            MyAdapter adapter = new MyAdapter(this,list);
            listView.setAdapter(adapter);
        }
    
        private void initData() {
            list = new ArrayList<Person>();
            Person p = null;
            for (int i = 0; i < 100; i++) {
                p = new Person("zhangsan" + i, i, "张三" + i);
                list.add(p);
            }
        }
    }

    由于我们把Adapter单独抽取成了一个类,因此要通过构造方法来传递上下文和数据两个参数。

    再来一个item.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >
        <LinearLayout 
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            >
            <TextView 
                android:id="@+id/username"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                />
            <TextView 
                android:id="@+id/nickname"
                android:layout_weight="1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                />
        </LinearLayout>
            <TextView 
                android:id="@+id/age"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                />
    
    </LinearLayout>
    

    • 第二步:简单的使用
      先来看看最简单的用法,即我们不使用ListView的回收机制,也不做任何优化,看看显示效果,前面三个方法和我们平时用的时候都是一样的,不做过多说明,重点是getView方法,在getView方法中,我们每次都重新获得一个新的view,很明显,这种方式简单粗暴,效率低下,而且除了getView方法中的position参数之外,其他的参数我们都没有用到。
        @Override
        public int getCount() {
            return list.size();
        }
    
        @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) {
            //简单使用
            View v = new View(context);
            TextView username = (TextView) v.findViewById(R.id.username);
            TextView nickname = (TextView) v.findViewById(R.id.nickname);
            TextView age = (TextView) v.findViewById(R.id.age);
            username.setText(list.get(position).getUsername());
            nickname.setText(list.get(position).getNickname());
            age.setText(list.get(position).getAge()+"");
            return v;
        }

    • 第三步:使用回收机制
      上面一种方式没有使用任何的回收策略,现在我们就来解决这个问题,看看怎么使用ListView中的回收机制。这里,我们在每次使用View之前都先判断view是否为空,为空的话我们再重新获得一个View,否则就使用之前的view.
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            // 简单使用
            // View v = LayoutInflater.from(context).inflate(R.layout.item, null);
            // TextView username = (TextView) v.findViewById(R.id.username);
            // TextView nickname = (TextView) v.findViewById(R.id.nickname);
            // TextView age = (TextView) v.findViewById(R.id.age);
            // username.setText(list.get(position).getUsername());
            // nickname.setText(list.get(position).getNickname());
            // age.setText(list.get(position).getAge()+"");
    
            // 使用ListView回收机制
            if (convertView == null)
                convertView = LayoutInflater.from(context).inflate(R.layout.item,
                        null);
             TextView username = (TextView) convertView.findViewById(R.id.username);
             TextView nickname = (TextView) convertView.findViewById(R.id.nickname);
             TextView age = (TextView) convertView.findViewById(R.id.age);
             username.setText(list.get(position).getUsername());
             nickname.setText(list.get(position).getNickname());
             age.setText(list.get(position).getAge()+"");
            return convertView;
        }

    • 第四步:减少findViewById的使用

    上面已经解决了回收item的问题,但是每次都要findViewById依然是非常耗时,所以这里我们将要使用一个ViewHolder来解决这个问题。所有item中的控件我们都在ViewHolder这个类中来说明,然后在实例化convertView的时候把ViewHolder保存在convertView中,在后面的使用中直接从convertView中获得ViewHolder。这样就避免了每次findViewById,尽量节省显示时间。

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            // 简单使用
            // View v = LayoutInflater.from(context).inflate(R.layout.item, null);
            // TextView username = (TextView) v.findViewById(R.id.username);
            // TextView nickname = (TextView) v.findViewById(R.id.nickname);
            // TextView age = (TextView) v.findViewById(R.id.age);
            // username.setText(list.get(position).getUsername());
            // nickname.setText(list.get(position).getNickname());
            // age.setText(list.get(position).getAge()+"");
    
            // 使用ListView回收机制
            // if (convertView == null)
            // convertView = LayoutInflater.from(context).inflate(R.layout.item,
            // null);
            // TextView username = (TextView)
            // convertView.findViewById(R.id.username);
            // TextView nickname = (TextView)
            // convertView.findViewById(R.id.nickname);
            // TextView age = (TextView) convertView.findViewById(R.id.age);
            // username.setText(list.get(position).getUsername());
            // nickname.setText(list.get(position).getNickname());
            // age.setText(list.get(position).getAge()+"");
    
            // 终极版
            ViewHolder viewHolder;
            if (convertView == null) {
                viewHolder = new ViewHolder();
                convertView = LayoutInflater.from(context).inflate(R.layout.item,
                        null);
                viewHolder.username = (TextView) convertView
                        .findViewById(R.id.username);
                viewHolder.nickname = (TextView) convertView
                        .findViewById(R.id.nickname);
                viewHolder.age = (TextView) convertView.findViewById(R.id.age);
                convertView.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) convertView.getTag();
            }
            viewHolder.username.setText(list.get(position).getUsername());
            viewHolder.nickname.setText(list.get(position).getNickname());
            viewHolder.age.setText(list.get(position).getAge() + "");
            return convertView;
        }

    • 第五布:三种方式比较
      上面我们介绍了三种方式,孰优孰劣,还是要数据说话,我们在getView开始和结束的时候加上时间统计方法,看看三种方式到底花费了多少时间。真是不比不知道,一比吓一跳。
      这里写图片描述
      这里写图片描述
      这里写图片描述
      不使用回收机制真的太可怕了!!!

    • 总结
      为了使我们的程序获得良好的性能,建议大家使用上文中第四步介绍的方式来使用BaseAdapter。

    本项目完整代码下载


  • 相关阅读:
    mvc中使用Hangfire处理后台任务
    mvc中图片的保存和显示
    WebVTT 及 HTML5 <track> 元素简介
    vs2015发布网站至azure web应用服务
    jquery上传大文件至azure blob存储
    dapper利用DynamicParameters构建动态参数查询
    aspnetcore的那些actionresult们
    vs2015 debugger,unable to attach to application iisexpress.exe
    ASP.NET’s compilation system
    Introducing .NET Standard
  • 原文地址:https://www.cnblogs.com/qitian1/p/6461763.html
Copyright © 2011-2022 走看看