Android杂谈--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;}@Overridepublic int getCount() {// How many items are in the data set represented by this Adapter.(在此适配器中所代表的数据集中的条目数)
            return 0;}@Overridepublic Object getItem(int position) {// Get the data item associated with the specified position in the data set.(获取数据集中与指定索引对应的数据项)
            return null;}@Overridepublic long getItemId(int position) {// Get the row id associated with the specified position in the list.(取在列表中与指定索引对应的行id)
            return 0;}@Overridepublic 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,设置资源,严重影响性能,所以从一开始就不要用这种方式

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

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

    //在外面先定义,ViewHolder静态类
    static class ViewHolder{public ImageView img;public TextView title;public TextView info;}
//然后重写getView
        @Overridepublic 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" ><ListViewandroid: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" ><ImageViewandroid: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"><TextViewandroid: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;@Overridepublic 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);}@Overridepublic int getCount() {//How many items are in the data set represented by this Adapter.//在此适配器中所代表的数据集中的条目数
            return data.size();}@Overridepublic Object getItem(int position) {// Get the data item associated with the specified position in the data set.//获取数据集中与指定索引对应的数据项
            return position;}@Overridepublic 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.//获取一个在数据集中指定索引的视图来显示数据
        @Overridepublic 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};@Overridepublic 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(){@Overridepublic 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;}@Overridepublic int getCount() {//返回图片数组大小
            return pics.length;}@Overridepublic Object getItem(int position) {//根据选中项返回索引位置
            return position;}@Overridepublic long getItemId(int position) {//根据选中项id返回索引位置
            return position;}//未优化的getView,这部分可以使用recycle()释放内存、或者BitmapFacotry.Options缩小,或者软引用,或者控制图片资源大小等等很多方法,找时间专门写
        @Overridepublic 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的使用相关推荐

  1. Android杂谈--ListView之BaseAdapter的使用一(转)

    BaseAdapter是直接继承自接口类Adapter的,使用BaseAdapter时需要重写很多方法      BaseAdapter与其他Adapter有些不一样,其他的Adapter可以直接在其 ...

  2. Android杂谈--ListView之BaseAdapter的使用二(转)

    实例二:Gallery上应用BaseAdapter main.xml <?xml version="1.0" encoding="utf-8"?> ...

  3. Android杂谈--ListView之SimpleAdapter的使用

    Android杂谈--ListView之SimpleAdapter的使用 SimpleAdapter SimpleAdapter是扩展性最好的适配器,可以定义各种你想要的布局,而且使用很方便 Simp ...

  4. Android杂谈--ListView之ArrayAdapter的使用

    Android杂谈--ListView之ArrayAdapter的使用 ArrayAdapter 总是感觉写自己的博客才更能够学到东西,网上尽管有很多好的资料,但是参差不齐,需要浪费大量时间才能够找到 ...

  5. android 自定义baseadapter listview,android之ListView和BaseAdapter的组合使用

    BaseAdapter是基本适配器,功能强大,凡是能用ArrayAdapter和SimpleAdapter解决的,都可以使用BaseAdapter解决. BaseAdapter是一个抽象类,所以需要自 ...

  6. android的listview+BaseAdapter的例子

    准备一个listview的xml,绑定到activity里面的listView的变量 准备一个继承自BaseAdapter的的MyAdapter,构造函数里面传入一个datasource的array, ...

  7. Android Listview 自定义BaseAdapter的实现及Listview优化示例

    上一篇文章中我们讲了Android Listview SimpleAdapter的使用完整示例(实现用户列表)_左眼看成爱的博客-CSDN博客 本示例实现的效果图: 每个item中的checkbox选 ...

  8. 我的Android进阶之旅------Android二级ListView列表的实现

    实现如下图所示的二级列表效果 首先是在布局文件中,布局两个ListView,代码如下: <LinearLayout xmlns:android="http://schemas.andr ...

  9. android之ListView和adapter配合显示图片和文字列表

    listView页面布局:layout/activity_main.xml: <LinearLayout xmlns:android="http://schemas.android.c ...

最新文章

  1. SAP SD基础知识之促销计划 (Agreements)
  2. LeetCode Algorithm 268. 丢失的数字
  3. ActionContextCleanUp作用
  4. sql server2008给数据表,字段,添加修改注释
  5. python温度转换代码分析_Python温度转换实例分析
  6. ubuntu更改屏幕界面大小和中文
  7. 继承ViewGroup研究(2)--在XML中使用ViewGroup初探
  8. AngularJs ui-router 路由的简单介绍
  9. nginx-反向代理笔记
  10. Delphi 7 升级到 Delphi 2010 总结
  11. Ubuntu 安装Qt以及配置
  12. 电商后台管理项目知识点总结
  13. 用PPT就可以做印章?是的,超简单超逼真,教你一分钟搞定
  14. 先写接口文档还是先开发
  15. 说说数据一致性有哪几种?
  16. 分享一款光谱分析软件(离线分析软件,导入光谱数据即可分析),功能超级多,超级强大,计算荧光量子效率,发射光谱的拉曼峰,计算共振能量转移(FRET)效率等
  17. Matlab 多项式展开或化简(即提取公因式
  18. centos7的scp命令_Linux scp命令
  19. win10上成功运行faster-rcnn.pytorch-1.0
  20. Eclips配置模板消息

热门文章

  1. python中碰撞的代码_Python…Tkinter碰撞
  2. 通过css3制作熊在冰川奔跑效果(animation、精灵图)
  3. 仿土豆网显示隐藏遮罩案例(HTML、CSS)
  4. jQuery天猫商品分类导航菜单
  5. mpvue 初始化微信小程序
  6. TypeScript学习(六):函数的定义及特性
  7. php foreach 不等于_你不知道的接口测试之简单的开始
  8. 7个JavaScript在IE和Firefox浏览器下的差异写法
  9. 竹间智能B轮3000万美元融资,打造业内领先的对话机器人及多模态情感计算平台...
  10. 我们能用RNN写策略吗?