`
u011721609
  • 浏览: 45459 次
社区版块
存档分类
最新评论

ListView之BaseAdapter的使用

 
阅读更多

话说开发用了各种Adapter之后感觉用的最舒服的还是BaseAdapter,尽管使用起来比其他适配器有些麻烦,但是使用它却能实现很多自己喜欢的列表布局,比如ListView、GridView、Gallery、Spinner等等。它是直接继承自接口类Adapter的,使用BaseAdapter时需要重写很多方法,其中最重要的当属getView,因为这会涉及到ListView优化等问题,其他的方法可以参考链接的文章

BaseAdapter与其他Adapter有些不一样,其他的Adapter可以直接在其构造方法中进行数据的设置,比如

SimpleAdapter adapter = new SimpleAdapter(this, getData(), R.layout.list_item, new String[]{"img","title","info",new int[]{R.id.img, R.id.title, R.id.info}});

但是在BaseAdapter中需要实现一个继承自BaseAdapter的类,并且重写里面的很多方法,例如

复制代码
class MyAdapter extends BaseAdapter
    {
        private Context context;
        public MyAdapter(Context context)
        {
            this.context = context;
        }
        @Override
        public int getCount() {
            // How many items are in the data set represented by this Adapter.(在此适配器中所代表的数据集中的条目数)
            return 0;
        }

        @Override
        public Object getItem(int position) {
            // Get the data item associated with the specified position in the data set.(获取数据集中与指定索引对应的数据项)
            return null;
        }

        @Override
        public long getItemId(int position) {
            // Get the row id associated with the specified position in the list.(取在列表中与指定索引对应的行id)
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            // Get a View that displays the data at the specified position in the data set.
            return null;
        }
        
    }
复制代码

这里面没什么难度,但是这个getView方法必须好好处理,也是最麻烦的

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

复制代码
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View item = mInflater.inflate(R.layout.list_item, null);
            ImageView img = (ImageView)item.findViewById(R.id.img) 
            TextView title = (TextView)item.findViewById(R.id.title);
            TextView info = (TextView)item.findViewById(R.id.info);
            img.setImageResource(R.drawable.ic_launcher);
            title.setText("Hello");
            info.setText("world");
            
            return item;
        }
复制代码

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

复制代码
        public View getView(int position, View convertView, ViewGroup parent) {
            if(convertView == null)
            {
                convertView = mInflater.inflate(R.layout.list_item, null);
            }
            
            ImageView img = (ImageView)convertView.findViewById(R.id.img) 
            TextView title = (TextView)convertView.findViewById(R.id.title);
            TextView info = (TextView)ConvertView.findViewById(R.id.info);
            img.setImageResource(R.drawable.ic_launcher);
            title.setText("Hello");
            info.setText("world");
            
            return convertView;
        }
复制代码

第三种ListView优化:通过convertView+ViewHolder来实现,ViewHolder就是一个静态类,使用 ViewHolder 的关键好处是缓存了显示数据的视图(View),加快了 UI 的响应速度。

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

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

复制代码
    //在外面先定义,ViewHolder静态类
    static class ViewHolder
    {
        public ImageView img;
        public TextView title;
        public TextView info;
    }
//然后重写getView
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder;
            if(convertView == null)
            {
                holder = new ViewHolder();
                convertView = mInflater.inflate(R.layout.list_item, null);
                holder.img = (ImageView)item.findViewById(R.id.img) 
                holder.title = (TextView)item.findViewById(R.id.title);
                holder.info = (TextView)item.findViewById(R.id.info);
                convertView.setTag(holder);
            }else
            {
                holder = (ViewHolder)convertView.getTag();
                holder.img.setImageResource(R.drawable.ic_launcher);
                holder.title.setText("Hello");
                holder.info.setText("World");
            }
            
            return convertView;
        }
复制代码

到这里,可能会有人问ViewHolder静态类结合缓存convertView与直接使用convertView有什么区别吗,是否重复了

在这里,官方给出了解释

提升Adapter的两种方法

To work efficiently the adapter implemented here uses two techniques:
-It reuses the convertView passed to getView() to avoid inflating View when it is not necessary

(译:重用缓存convertView传递给getView()方法来避免填充不必要的视图)
-It uses the ViewHolder pattern to avoid calling findViewById() when it is not necessary

(译:使用ViewHolder模式来避免没有必要的调用findViewById():因为太多的findViewById也会影响性能)
ViewHolder类的作用
-The ViewHolder pattern consists in storing a data structure in the tag of the view
returned by getView().This data structures contains references to the views we want to bind data to,
thus avoiding calling to findViewById() every time getView() is invoked

(译:ViewHolder模式通过getView()方法返回的视图的标签(Tag)中存储一个数据结构,这个数据结构包含了指向我们

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

实例一:用BaseAdapter来自定义ListView布局
main.xml

复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <ListView
        android:id="@+id/lv"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:fastScrollEnabled="true"
        />

</LinearLayout>
复制代码

list_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="horizontal" >

    <ImageView
        android:id="@+id/img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
    <LinearLayout 
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        >
        <TextView
            android:id="@+id/tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="20sp"
        />
        <TextView 
            android:id="@+id/info"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="14sp"
            />
    </LinearLayout>
    

</LinearLayout>
复制代码

Activity

复制代码
package com.loulijun.demo17;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

public class Demo17Activity extends Activity {
    private ListView lv;
    private List<Map<String, Object>> data;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        lv = (ListView)findViewById(R.id.lv);
        //获取将要绑定的数据设置到data中
        data = getData();
        MyAdapter adapter = new MyAdapter(this);
        lv.setAdapter(adapter);
    }
    
    private List<Map<String, Object>> getData()
    {
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        Map<String, Object> map;
        for(int i=0;i<10;i++)
        {
            map = new HashMap<String, Object>();
            map.put("img", R.drawable.ic_launcher);
            map.put("title", "跆拳道");
            map.put("info", "快乐源于生活...");
            list.add(map);
        }
        return list;
    }
    
    //ViewHolder静态类
    static class ViewHolder
    {
        public ImageView img;
        public TextView title;
        public TextView info;
    }
    
    public class MyAdapter extends BaseAdapter
    {    
        private LayoutInflater mInflater = null;
        private MyAdapter(Context context)
        {
            //根据context上下文加载布局,这里的是Demo17Activity本身,即this
            this.mInflater = LayoutInflater.from(context);
        }

        @Override
        public int getCount() {
            //How many items are in the data set represented by this Adapter.
            //在此适配器中所代表的数据集中的条目数
            return data.size();
        }

        @Override
        public Object getItem(int position) {
            // Get the data item associated with the specified position in the data set.
            //获取数据集中与指定索引对应的数据项
            return position;
        }

        @Override
        public long getItemId(int position) {
            //Get the row id associated with the specified position in the list.
            //获取在列表中与指定索引对应的行id
            return position;
        }
        
        //Get a View that displays the data at the specified position in the data set.
        //获取一个在数据集中指定索引的视图来显示数据
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ViewHolder holder = null;
            //如果缓存convertView为空,则需要创建View
            if(convertView == null)
            {
                holder = new ViewHolder();
                //根据自定义的Item布局加载布局
                convertView = mInflater.inflate(R.layout.list_item, null);
                holder.img = (ImageView)convertView.findViewById(R.id.img);
                holder.title = (TextView)convertView.findViewById(R.id.tv);
                holder.info = (TextView)convertView.findViewById(R.id.info);
                //将设置好的布局保存到缓存中,并将其设置在Tag里,以便后面方便取出Tag
                convertView.setTag(holder);
            }else
            {
                holder = (ViewHolder)convertView.getTag();
            }
            holder.img.setBackgroundResource((Integer)data.get(position).get("img"));
            holder.title.setText((String)data.get(position).get("title"));
            holder.info.setText((String)data.get(position).get("info"));
            
            return convertView;
        }
        
    }
}
复制代码

运行结果如下:


实例二:Gallery上应用BaseAdapter

main.xml

复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >
    
    <ImageView 
        android:id="@+id/img"
        android:layout_width="480px"
        android:layout_height="480px"
        android:layout_gravity="center"
        />
    <Gallery 
        android:id="@+id/gallery"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:spacing="3dp"
        android:layout_gravity="bottom"
        />

</LinearLayout>
复制代码

Activity:这部分里的getView没有优化,调试了很久还没调通,暂时还是用的最基本的方法。会专门找个时间把Gallery内存泄露的部分写一下,因为图片资源很多的时候会引起out of memory的错误

复制代码
package com.loulijun.demo16;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.ImageView;

public class Demo16Activity extends Activity {
    private Gallery mGallery;
    private ImageView mImg;
    //图片数组
    private int[] pics = {
            R.drawable.pic1,
            R.drawable.pic2,
            R.drawable.pic3,
            R.drawable.pic4,
            R.drawable.pic5,
            R.drawable.pic6
    };
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mImg = (ImageView)findViewById(R.id.img);
        mGallery = (Gallery)findViewById(R.id.gallery);
        MyAdapter adapter = new MyAdapter(this);
        mGallery.setAdapter(adapter);
        mGallery.setOnItemClickListener(new Gallery.OnItemClickListener()
        {

            @Override
            public void onItemClick(AdapterView<?> adapter, View view, int position,
                    long arg3) {
                mImg.setImageResource(pics[position]);
            }
            
        });
    }
    
    //内部类
    class MyAdapter extends BaseAdapter
    {
        //用来接收传递过来的Context上下文对象
        private Context context;

        //构造函数
        public MyAdapter(Context context)
        {
            this.context = context;
        }
        @Override
        public int getCount() {
            //返回图片数组大小
            return pics.length;
        }

        @Override
        public Object getItem(int position) {
            //根据选中项返回索引位置
            return position;
        }

        @Override
        public long getItemId(int position) {
            //根据选中项id返回索引位置
            return position;
        }
        //未优化的getView,这部分可以使用recycle()释放内存、或者BitmapFacotry.Options缩小,或者软引用,或者控制图片资源大小等等很多方法,找时间专门写
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            ImageView img = new ImageView(context);
            img.setAdjustViewBounds(true);
            img.setImageResource(pics[position]);
            img.setScaleType(ImageView.ScaleType.FIT_XY);
            img.setLayoutParams(new Gallery.LayoutParams(120,120));
            
            return img;
        }    
    }
}
复制代码

运行效果:原理都是一样,只不过是布局加载的时候会有区别,不过就这个小区别也让人够恼火的了



文章精选:

http://www.cnblogs.com/over140/archive/2010/12/03/1895128.html

分享到:
评论

相关推荐

    Android之ListView+BaseAdapter左右按键切换

    在这个"Android之ListView+BaseAdapter左右按键切换"的项目中,我们将会深入探讨如何利用ListView结合BaseAdapter实现通过键盘左右按键来切换并更新ListView中的数据。BaseAdapter是Android系统提供的一种适配器,它...

    【android】ListView之BaseAdapter使用详解

    1. 为什么使用BaseAdapter? ListView需要设置数据适配,就是添加你需要显示的内容,所谓适配就是数据与视图之间的桥梁; 而ListView有几种适配器: BaseAdapter:顾名思义,最基础的适配器,有四个抽象方法,可以...

    android BaseAdapter listView优化

    BaseAdapter则是与ListView配合使用的数据适配器,负责将数据绑定到ListView的各个视图上。本篇文章将深入探讨ListView与BaseAdapter的工作原理,并详细介绍如何进行性能优化。 首先,我们来理解一下Adapter在...

    ListView和BaseAdapter搭配Button点击事件获取不同Item

    它与BaseAdapter结合使用,可以实现数据的动态加载和界面的复用。在这个场景中,我们要讨论的重点是如何在ListView中的每个Item(即列表项)上添加Button,并处理这些Button的点击事件,以便根据点击的Button获取...

    ListView_BaseAdapter填充Conver+view

    本教程将深入讲解如何使用BaseAdapter填充ListView,并实现类似QQ聊天列表的效果。 首先,我们需要了解ListView的工作原理。ListView通过复用已存在的View(convertView)来提高性能,当用户滚动时,不再显示的Item...

    webview与ListView、BaseAdapter实现方法

    `BaseAdapter`是`ListView`的数据适配器,它帮助我们将数据源与列表视图的各个项进行绑定。下面将详细介绍这三者的核心概念、实现方法以及它们在实际应用中的结合。 ### WebView `WebView`是Android SDK提供的一种...

    ListView的使用自定义BaseAdapter

    本篇主要讲解如何在Android Studio中使用ListView,并结合自定义的BaseAdapter来实现数据的绑定和显示。 首先,我们需要在布局文件中添加ListView组件。在res/layout目录下的xml布局文件中,可以这样定义一个...

    Android中ListView常用方式:使用BaseAdapter

    在Android开发中,ListView是一个非常重要的组件,常用于展示大量数据列表。本篇文章将深入探讨如何在Android中使用BaseAdapter来...了解并熟练掌握BaseAdapter的使用,对于Android开发者来说是非常重要的技能之一。

    Android中ListView,SQLite,BaseAdapter的结合源码

    在Android开发中,ListView、SQLite和BaseAdapter是三个至关重要的组件,它们共同协作,使得应用程序能够展示和管理大量数据。ListView是一种可滚动的视图,用于显示一系列项,而SQLite是一个轻量级的数据库系统,...

    用BaseAdapter实现的ListView

    在`ListViewBaseAdapter`这个文件中,很可能包含了实现上述逻辑的代码。可能有自定义的布局文件,用于定义ListView项的外观,还有可能包含了一些业务逻辑,如数据处理或事件监听。 使用BaseAdapter的一个优点是它...

    SQLite 和 listview baseAdapter结合的例子

    在这个例子中,我们关注的是如何将SQLite数据库的数据通过BaseAdapter展现到ListView上。 首先,我们需要创建一个SQLite数据库。这通常涉及到以下步骤: 1. 创建一个SQLiteOpenHelper子类,重写`onCreate()`和`...

    实现ListView过滤功能,继承于BaseAdapter,非ArrayAdapter。

    以上就是如何在不使用ArrayAdapter的情况下,通过继承BaseAdapter实现ListView的过滤功能。这个过程涉及到了数据源管理、过滤逻辑的实现以及适配器与ListView之间的通信,是一个比较全面的Android组件定制案例。通过...

    listview+BaseAdapter + AsyncTask异步请求网络 + LruCache缓存图片

    在Android开发中,ListView是展示大量数据的常用控件,而BaseAdapter是连接ListView与数据源的关键组件。本文将深入探讨如何结合BaseAdapter、AsyncTask以及LruCache来实现高效、流畅的网络图片加载。 首先,`...

    BaseAdapter的使用与优化

    在Android开发中,ListView是展示大量数据常用的组件,而BaseAdapter是它的重要伙伴,用于将数据绑定到ListView的各个Item视图上。本教程通过一个Eclipse下的Android工程实例,详细讲解了BaseAdapter的使用方法以及...

    BaseAdapter_listview

    总结起来,"BaseAdapter_listview"实例展示了如何使用BaseAdapter自定义ListView的适配器,以便将任意数据源(如ArrayList)的数据绑定到ListView中显示。这是Android开发中常见的数据绑定技术,对于理解和提升...

    listview简单的demo。BaseAdapter的使用

    接下来,我们将深入探讨ListView与BaseAdapter的关系、BaseAdapter的使用以及getView方法的优化。 1. **ListView的基本概念**:ListView是Android中的一个视图组件,它可以滚动显示多个行项目。它通常与其他适配器...

    ListView优化+baseAdapter

    1. **数据模型**:在使用BaseAdapter时,我们需要定义一个数据模型类,用于存储ListView要显示的数据。例如,我们可以创建一个包含文本和图片URL的`MyItem`类,然后在Adapter中使用这个类实例化每个Item的数据。 2....

    ListView_baseAdapter

    ListView_baseAdapter 那是带有Customcell文件的UITable 开发环境。 Android Studio版本:2.3 作业系统版本:OS X EI Caption 10.11.6 部署目标:API 23 模拟器版本:Android 6.0 您可以在我的YouTube频道和...

    listview 通过继承BaseAdapter来实现

    BaseAdapter是ListView的数据适配器,它负责将数据绑定到ListView的各个视图项。本篇将详细讲解如何通过继承BaseAdapter来实现ListView的功能,这对于初学者来说是非常重要的基础知识。 1. **ListView的基本概念** ...

    使用BaseAdapter完成listview中带图片item

    本示例将详细介绍如何使用BaseAdapter来实现一个ListView,其中每个Item都包含图片。 BaseAdapter是Android系统提供的适配器类,它是Adapter接口的一个实现,用于将数据与ListView的视图绑定。通过自定义...

Global site tag (gtag.js) - Google Analytics