ListView优化之BaseAdapter使用小心得

时间:2022-10-06 16:39:31


(初学者)

当我们需要通过滚动屏幕来显示我们需要的item时候,如果一次次findViewById的话效率极低。这里BaseAdapter这个库可以解决这个问题。

通过改写库里面getView()方法,可以实现旧item的缓存,以及再一次使用时候的调出。

BaseAdaper类的介绍:BaseAdapter就是Android应用程序中经常用到的基础数据适配器,它实现了ListAdapter和SpinnerAdapter两个接口。且其主要用途是将一组数据传到像ListView、Spinner、Gallery及GridView等UI显示组件。

Android中Adapter类其实就是把数据源绑定到指定的View上,然后再返回该View,而返回来的这个View就是ListView中的某一行item。这里返回来的View正是由于我们的Adapter中的getView方法返回的。也就是说当我们想做一个列表形式的界面时,我们通常会用到Adapter类,而BaseAdapter则是其中一个很灵活的类。我们可以通过改写BaseAdapter类中的方法来灵活的将数据传到UI显示组件进行显示。

getView()介绍:这个方法是BaseAdapter类中最重要的一个部分,合理的改写此部分可以很好地提高代码效率。这里大概有3种getView()的写法。

第一种:没有任何处理,不建议这样写。如果数据量少看将就,但是如果列表项数据量很大的时候,会每次都重新创建View,设置资源,严重影响性能,所以从一开始就不要用这种方式

1.@Override
2. public View getView(int position, View convertView, ViewGroup parent) {
3. View item = mInflater.inflate(R.layout.list_item, null);
4. ImageView img = (ImageView)item.findViewById(R.id.img)
5. TextView title = (TextView)item.findViewById(R.id.title);
6. TextView info = (TextView)item.findViewById(R.id.info);
7. img.setImageResource(R.drawable.ic_launcher);
8. title.setText("Hello");
9. info.setText("world");
10.
11. return item;
12. }

第二种:通过缓存convertView,这种利用缓存contentView的方式可以判断如果缓存中不存在View才创建View,如果已经存在可以利用缓存中的View,提升了性能

1.public View getView(int position, View convertView, ViewGroup parent) {
2. if(convertView == null)
3. {
4. convertView = mInflater.inflate(R.layout.list_item, null);
5. }
6.
7. ImageView img = (ImageView)convertView.findViewById(R.id.img)
8. TextView title = (TextView)convertView.findViewById(R.id.title);
9. TextView info = (TextView)ConvertView.findViewById(R.id.info);
10. img.setImageResource(R.drawable.ic_launcher);
11. title.setText("Hello");
12. info.setText("world");
13.
14. return convertView;
15. }
第三种:通过convertView+ViewHolder来实现,ViewHolder就是一个静态类,使用 ViewHolder 的关键好处是缓存了显示数据的视图(View),加快了 UI 的响应速度。

当我们判断 convertView == null  的时候,如果为空,就会根据设计好的List的Item布局(XML),来为convertView赋值,并生成一个viewHolder来绑定converView里面的各个View控件(XML布局里面的那些控件)。再用convertView的setTag将viewHolder设置到Tag中,以便系统第二次绘制ListView时从Tag中取出。(看下面代码中)

如果convertView不为空的时候,就会直接用convertView的getTag(),来获得一个ViewHolder。 

1.//在外面先定义,ViewHolder静态类
2.static class ViewHolder
3.{
4. public ImageView img;
5. public TextView title;
6. public TextView info;
7.}
8.//然后重写getView
9.@Override
10.public View getView(int position, View convertView, ViewGroup parent) {
11. ViewHolder holder;
12. if(convertView == null)
13. {
14. holder = new ViewHolder();
15. convertView = mInflater.inflate(R.layout.list_item, null);
16. holder.img = (ImageView)item.findViewById(R.id.img)
17. holder.title = (TextView)item.findViewById(R.id.title);
18. holder.info = (TextView)item.findViewById(R.id.info);
19. convertView.setTag(holder);
20. }else
21. {
22. holder = (ViewHolder)convertView.getTag();
23. }
24. holder.img.setImageResource(R.drawable.ic_launcher);
25. holder.title.setText("Hello");
26. holder.info.setText("World");
27. }
28.
29. return convertView;
30.}

 其中第二种和第三种最大的区别就在于,ViewHolder模式通过getView()方法返回的视图的标签(Tag)中存储一个数据结构,这个数据结构包含了指向我们

要绑定数据的视图的引用,从而避免每次调用getView()的时候调用findViewById()


这里再简单介绍一下getView中比较重要的类:

ViewHolder

ViewHolder通常出现在适配器里,为的是listview滚动的时候快速设置值,而不必每次都重新创建很多对象,从而提升性能。在android开发中Listview是一个很重要的组件,它以列表的形式根据数据的长自适应展示具体内容,用户可以*的定义listview每一列的布局,但当listview有大量的数据需要加载的时候,会占据大量内存,影响性能,这时候就需要按需填充并重新使用view来减少对象的创建。

可以看到代码部分定义一个viewholder类,屏幕每次显示一个item时候会调用一次getView()方法,通过setTag()将我们所显示的item保存起来缓存在我们的ViewHolder类中,从而在我们下一次显示旧item时候直接从ViewHolder中通过getTag()调出。



        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
             ViewHolder holder;
            if (convertView == null) {
                     convertView = mInflater.inflate(R.layout.item,
    null);
                     holder = new ViewHolder();
                    /*得到各个控件的对象*/
                    holder.title = (TextView) convertView.findViewById(R.id.ItemTitle);
                    holder.text = (TextView) convertView.findViewById(R.id.ItemText);
                    holder.bt = (Button) convertView.findViewById(R.id.ItemButton);
                    convertView.setTag(holder);//绑定ViewHolder对象
                   }
    else{
                    holder = (ViewHolder)convertView.getTag();//取出ViewHolder对象
                  }
            /*设置TextView显示的内容,即我们存放在动态数组中的数据*/
            holder.title.setText(getDate().get(position).get("ItemTitle").toString());
            holder.text.setText(getDate().get(position).get("ItemText").toString());
            return convertView;
        }