首页 Java java教程 Android杂谈--ListView之BaseAdapter的使用

Android杂谈--ListView之BaseAdapter的使用

Dec 13, 2016 pm 04:41 PM
android

话说开发用了各种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",newint[]{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 
        publicint getCount() { 
            // How many items are in the data set represented by this Adapter.(在此适配器中所代表的数据集中的条目数) 
            return0; 
        } 
 
        @Override 
        public Object getItem(int position) { 
            // Get the data item associated with the specified position in the data set.(获取数据集中与指定索引对应的数据项) 
            returnnull; 
        } 
 
        @Override 
        publiclong getItemId(int position) { 
            // Get the row id associated with the specified position in the list.(取在列表中与指定索引对应的行id) 
            return0; 
        } 
 
        @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. 
            returnnull; 
        } 
         
    }
登录后复制

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

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

//在外面先定义,ViewHolder静态类 
    staticclass 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

<?xmlversion="1.0"encoding="utf-8"?> 
<LinearLayoutxmlns: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

<?xmlversion="1.0"encoding="utf-8"?> 
<LinearLayoutxmlns: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; 
 
publicclass Demo17Activity extends Activity { 
    private ListView lv; 
    private List<Map<String, Object>> data; 
    @Override 
    publicvoid 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静态类 
    staticclass ViewHolder 
    { 
        public ImageView img; 
        public TextView title; 
        public TextView info; 
    } 
     
    publicclass MyAdapter extends BaseAdapter 
    {     
        private LayoutInflater mInflater = null; 
        private MyAdapter(Context context) 
        { 
            //根据context上下文加载布局,这里的是Demo17Activity本身,即this 
            this.mInflater = LayoutInflater.from(context); 
        } 
 
        @Override 
        publicint 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 
        publiclong 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; 
        } 
         
    } 
}
登录后复制

运行结果如下:

用BaseAdapter来自定义ListView布局

实例二:Gallery上应用BaseAdapter

main.xml

<?xmlversion="1.0"encoding="utf-8"?> 
<LinearLayoutxmlns: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; 
 
publicclass Demo16Activity extends Activity { 
    private Gallery mGallery; 
    private ImageView mImg; 
    //图片数组 
    privateint[] pics = { 
            R.drawable.pic1, 
            R.drawable.pic2, 
            R.drawable.pic3, 
            R.drawable.pic4, 
            R.drawable.pic5, 
            R.drawable.pic6 
    }; 
    @Override 
    publicvoid 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 
            publicvoid 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 
        publicint getCount() { 
            //返回图片数组大小 
            return pics.length; 
        } 
 
        @Override 
        public Object getItem(int position) { 
            //根据选中项返回索引位置 
            return position; 
        } 
 
        @Override 
        publiclong 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; 
        }     
    } 
}
登录后复制

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

Gallery上应用BaseAdapter

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

新报告对传闻中的三星 Galaxy S25、Galaxy S25 Plus 和 Galaxy S25 Ultra 相机升级进行了严厉的评估 新报告对传闻中的三星 Galaxy S25、Galaxy S25 Plus 和 Galaxy S25 Ultra 相机升级进行了严厉的评估 Sep 12, 2024 pm 12:23 PM

最近几天,Ice Universe 不断披露有关 Galaxy S25 Ultra 的详细信息,人们普遍认为这款手机将是三星的下一款旗舰智能手机。除此之外,泄密者声称三星只计划升级一款相机

三星 Galaxy S25 Ultra 泄露了第一张渲染图,传闻中的设计变化被曝光 三星 Galaxy S25 Ultra 泄露了第一张渲染图,传闻中的设计变化被曝光 Sep 11, 2024 am 06:37 AM

OnLeaks 现在与 Android Headlines 合作,首次展示了 Galaxy S25 Ultra,几天前,他试图从他的 X(以前的 Twitter)粉丝那里筹集到 4,000 美元以上的资金,但失败了。对于上下文,嵌入在 h 下面的渲染图像

IFA 2024 | TCL 的 NXTPAPER 14 在性能上无法与 Galaxy Tab S10 Ultra 相媲美,但在尺寸上几乎可以与之媲美 IFA 2024 | TCL 的 NXTPAPER 14 在性能上无法与 Galaxy Tab S10 Ultra 相媲美,但在尺寸上几乎可以与之媲美 Sep 07, 2024 am 06:35 AM

除了发布两款新智能手机外,TCL 还发布了一款名为 NXTPAPER 14 的新 Android 平板电脑,其大屏幕尺寸是其卖点之一。 NXTPAPER 14 采用 TCL 标志性品牌哑光液晶面板 3.0 版本

Vivo Y300 Pro 在 7.69 毫米纤薄机身中配备 6,500 mAh 电池 Vivo Y300 Pro 在 7.69 毫米纤薄机身中配备 6,500 mAh 电池 Sep 07, 2024 am 06:39 AM

Vivo Y300 Pro刚刚全面亮相,它是最薄的中端Android手机之一,配备大电池。准确来说,这款智能手机的厚度仅为 7.69 毫米,但配备了 6,500 mAh 的电池。这与最近推出的容量相同

三星 Galaxy S24 FE 预计将以低于预期的价格推出,有四种颜色和两种内存选项 三星 Galaxy S24 FE 预计将以低于预期的价格推出,有四种颜色和两种内存选项 Sep 12, 2024 pm 09:21 PM

三星尚未就何时更新其 Fan Edition (FE) 智能手机系列提供任何提示。目前来看,Galaxy S23 FE 仍然是该公司的最新版本,于 2023 年 10 月年初推出。

新报告对传闻中的三星 Galaxy S25、Galaxy S25 Plus 和 Galaxy S25 Ultra 相机升级进行了严厉的评估 新报告对传闻中的三星 Galaxy S25、Galaxy S25 Plus 和 Galaxy S25 Ultra 相机升级进行了严厉的评估 Sep 12, 2024 pm 12:22 PM

最近几天,Ice Universe 不断披露有关 Galaxy S25 Ultra 的详细信息,人们普遍认为这款手机将是三星的下一款旗舰智能手机。除此之外,泄密者声称三星只计划升级一款相机

小米红米 Note 14 Pro Plus 上市,成为首款配备 Light Hunter 800 摄像头的高通 Snapdragon 7s Gen 3 智能手机 小米红米 Note 14 Pro Plus 上市,成为首款配备 Light Hunter 800 摄像头的高通 Snapdragon 7s Gen 3 智能手机 Sep 27, 2024 am 06:23 AM

Redmi Note 14 Pro Plus 现已正式成为去年 Redmi Note 13 Pro Plus 的直接后继产品(亚马逊售价 375 美元)。正如预期的那样,Redmi Note 14 Pro Plus与Redmi Note 14和Redmi Note 14 Pro一起成为Redmi Note 14系列的主角。李

iQOO Z9 Turbo Plus:可能增强的系列旗舰产品已开始预订 iQOO Z9 Turbo Plus:可能增强的系列旗舰产品已开始预订 Sep 10, 2024 am 06:45 AM

OnePlus的姐妹品牌iQOO的2023-4年产品周期可能即将结束;尽管如此,该品牌已宣布 Z9 系列的开发尚未结束。它的最终版,也可能是最高端的 Turbo+ 变体刚刚按照预测发布。时间

See all articles