【Android学习笔记系列】BaseAdapter适配器的介绍、使用及优化(详细)

来源:互联网 发布:ubuntu 输入法安装 编辑:程序博客网 时间:2024/05/18 01:45

什么是数据适配器


数据源(Data source)的格式是多种多样的,但是ListView的可以展示的格式却是有一定的要求的

作为适配器(Adapter)的作用就是将数据源中多种多样的数据格式转化为ListView可以展示的格式,建立数据源与ListView的一个适配关系,比如数据源的某某格式应该对应ListView支持的某某格式。并从中将数据的来源和数据的显示进行了解耦,降低了程序的耦合性,让程序更容易扩展。


ListView的显示与缓存机制




如果存在一百条数据,ListView不会一次性全部加载,它只会加载屏幕能够展示的数据,如图中的7条数据,当手指向上滑动的时候,Item1就会移除屏幕,它就会被回收到一个Recycler的View缓冲池中,而Item8就从会缓存池中取出来一个布局文件,并通过getView()重新设置好Item8要显示的数据,再插入画面中空位中


BaseAdapter通用适配器



getCount():就是这个ListView总共要显示多少条数据


使用步骤:

第一步,我们要建立好android的界面布局,首先是主要的ListView的布局界面

在activity_main.xml写一个ListView,代码如下:

activity_main.xml

<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="${relativePackage}.${activityClass}" >    <ListView        android:id="@+id/lv_main"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="@string/hello_world" /></RelativeLayout>

第二步,再新建一个item布局,作为ListView的子布局



布局文件如下:

item.xml

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >    <ImageView        android:id="@+id/iv_image"        android:layout_width="60dp"        android:layout_height="60dp"        android:src="@drawable/ic_launcher" />    <TextView        android:id="@+id/tv_title"        android:layout_width="match_parent"        android:layout_height="30dp"        android:layout_alignParentTop="true"        android:layout_toRightOf="@+id/iv_image"        android:gravity="center"        android:layout="@+id/iv_image"        android:text="title" />     <TextView         android:id="@+id/tv_content"         android:layout_width="match_parent"         android:layout_height="30dp"         android:layout_alignBottom="@+id/iv_image"         android:layout_alignLeft="@+id/tv_title"         android:layout_alignParentRight="true"         android:gravity="center_vertical"         android:layout="@+id/iv_image"         android:text="content" /></RelativeLayout>


这个布局是用来给ListView每一项Item显示内容的布局,效果如下




BaseAdapter之创建数据源

之前我们已经将ListView的item项布局已经建好了,但是我们还需要建立一个数据源,通过数据源来给item赋值。

第三步,创建数据源,这里新建一个Java类,叫做itemBean,作用是来封装item布局的三个数据,图片,title,content


ItemBean.java

package bnuz.lwj.listviewteacheing;public class ItemBean {public int ItemImageResid;public String ItemTitle;public String ItemContent;//构造方法public ItemBean(int itemImageResid, String itemTitle, String itemContent) {super();ItemImageResid = itemImageResid;ItemTitle = itemTitle;ItemContent = itemContent;}}

将数据封装起来,每一个ItemBean对象就对应一个Item布局的内容

第四步,我们要给数据源赋值,然后我们切换在MainActivity的onCreate()函数中写一个for循环,用于 赋值、调试

List<ItemBean> itemBeanList=new ArrayList<ItemBean>();for(int i=0;i<20;i++){itemBeanList.add(new ItemBean(R.drawable.ic_launcher,"我的标题"+i,"我是内容"+i));}

BaseAdapter之数据适配器初解

经过上面的操作,我们已经将数据源建立起来了,然后我们需要重写一个数据适配器

第五步、重写数据适配器,新建一个JAVA类,MyAdapter.java,继承于BaseAdapter,重写四个函数,我们可以看到这四个函数就是我们之间在上面介绍BaseAdapter通用适配器的时候图片所展示出来的四个函数(如果没看懂,就上去看上边的图片,BaseAdapter的基本结构)


为了从数据源中要获取传进来的数据,通常在适配器中对数据进行初始化

这里贴出前三个函数的重写方法,每一个函数的作用都写在了注释了,可以参考上边BaseAdapter的基本结构的图一一对应,好好琢磨,会想通的

//私人成员属性,用于保存传进来的数据private List <ItemBean> mList;//构造方法,用于初始化传进来的参数//这里需要传进来一个context对象来初始化 mInflaterpublic MyAdapter(Context context,List<ItemBean> list) {mList=list;mInflater=LayoutInflater.from(context);}@Overridepublic int getCount() {// 返回ListView需要显示的数据return mList.size();}@Overridepublic Object getItem(int position) {//所有的数据(集中)项数据都存放在mList中//取出对应索引的数据项的数据并返回return mList.get(position);}@Overridepublic long getItemId(int position) {// 返回某个数据项对应的索引return position;}

getView()的三种使用方法

第四个函数getView()即是最重要也是最复杂的一个函数,所以一定要弄懂这个函数。
同时这个函数,这里总结三个方法。

第一个方法仔细的总结一下,第二第三个方法就贴代码,不一一总结了。

第一个方法:

首先我们要在MyAdapter函数里,创建一个LayoutInflater对象,它的作用是将XML文件转化为一个View布局,然后 通过LayoutInflater.from(context)来初始化





然后在getView函数里,新定义一个View的对象来获取mInflater装载的item布局的对象。


然后我们需要将getItem()函数从数据源中取得并返回来的数据赋值我们的item.xml里的三个控件或则新定义一个ItemBean,再通过List集合的get索引(position)方法来获取在mList的数据项,在这里,我们使用第二种方法。

第一种方法的完整代码

@Overridepublic View getView(int position, View convertView, ViewGroup parent) {//这是最重要也是最复杂的方法//作用是返回每一项的内容//方法一、效率低下//将item.xml转化为View布局View view =mInflater.inflate(R.layout.item,null);ImageView imageView=(ImageView) view.findViewById(R.id.iv_image);TextView title=(TextView) view.findViewById(R.id.tv_title);TextView content=(TextView) view.findViewById(R.id.tv_content);//赋值ItemBean bean =mList.get(position);imageView.setImageResource(bean.ItemImageResid);title.setText(bean.ItemTitle);content.setText(bean.ItemContent);return view;}

但是方法一没有使用到ListView的缓存机制,这是对资源的极大浪费,效率低下,所以不推荐使用


第二个方法:

第二种方法的完整代码

@Overridepublic View getView(int position, View convertView, ViewGroup parent) {//这是最重要也是最复杂的方法//作用是返回每一项的内容//方法二、正常,利用了ListView的缓存机制,算入门,findViewById会浪费大量时间//如果为空:View未被实例化,缓存池中也无缓存,所以我们要主动为它赋一个Viewif(convertView==null){convertView=mInflater.inflate(R.layout.item,null);}ImageView imageView=(ImageView)convertView.findViewById(R.id.iv_image);TextView title=(TextView) convertView.findViewById(R.id.tv_title);TextView content=(TextView) convertView.findViewById(R.id.tv_content);//赋值ItemBean bean =mList.get(position);imageView.setImageResource(bean.ItemImageResid);title.setText(bean.ItemTitle);content.setText(bean.ItemContent);return convertView;}


第二种方法虽然使用了ListView的缓存机制,算入门方式,但是其中每次都会重复调用多次findViewById,也会浪费资源,所以谷歌的大佬提供了第三种方式


第三个方法:
首先在MyAdapter类里定义一个内部类ViewHolder类,作用就是为了避免重复的findViewById操作

//创建一个内部类,作业就是为了避免重复的findViewById操作class ViewHolder{//对应item.xml的三个控件public ImageView imageView;public TextView title;public TextView content;}
第三种方法的完整代码

@Overridepublic View getView(int position, View convertView, ViewGroup parent) {//这是最重要也是最复杂的方法//作用是返回每一项的内容//方法三、建议使用ViewHolder viewHolder;if(convertView==null){viewHolder=new ViewHolder();convertView=mInflater.inflate(R.layout.item,null);//将控件保存到viewHolder中viewHolder.imageView=(ImageView)convertView.findViewById(R.id.iv_image);viewHolder.title=(TextView) convertView.findViewById(R.id.tv_title);viewHolder.content=(TextView) convertView.findViewById(R.id.tv_content);//通过setTag将ViewHoler与convertView绑定convertView.setTag(viewHolder);}else{viewHolder=(ViewHolder) convertView.getTag();}ItemBean bean =mList.get(position);viewHolder.imageView.setImageResource(bean.ItemImageResid);viewHolder.title.setText(bean.ItemTitle);viewHolder.content.setText(bean.ItemContent);return convertView;}


作用就是通过ViewHodler,当converView为空的时候,我们为其赋值,并且通过converView.setTag(viewHolder)的方法将holder与converView进行绑定,之后的遍历中,每次只要通过converView的getTag()方法就能获取到converView的三个控件,避免了每次都通过findById这个方法去实例化三个控件。



MyAdapter.java

package bnuz.lwj.listviewteacheing;import java.util.List;import bnuz.lwj.listviewteacheing.ItemBean;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.TextView;public class MyAdapter extends BaseAdapter{//创建一个LayoutInflaterprivate LayoutInflater mInflater;//私人成员属性,用于保存传进来的数据private List <ItemBean> mList;//构造方法,用于初始化传进来的参数//这里需要传进来一个context对象来初始化 mInflaterpublic MyAdapter(Context context,List<ItemBean> list) {mList=list;mInflater=LayoutInflater.from(context);}@Overridepublic int getCount() {// 返回ListView需要显示的数据return mList.size();}@Overridepublic Object getItem(int position) {//所有的数据(集中)项数据都存放在mList中//取出对应索引的数据项的数据并返回return mList.get(position);}@Overridepublic long getItemId(int position) {// 返回某个数据项对应的索引return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {//这是最重要也是最复杂的方法//作用是返回每一项的内容//方法一、效率低下//将item.xml转化为View布局/*View view =mInflater.inflate(R.layout.item,null);ImageView imageView=(ImageView) view.findViewById(R.id.iv_image);TextView title=(TextView) view.findViewById(R.id.tv_title);TextView content=(TextView) view.findViewById(R.id.tv_content);//赋值ItemBean bean =mList.get(position);imageView.setImageResource(bean.ItemImageResid);title.setText(bean.ItemTitle);content.setText(bean.ItemContent);return view;*///方法二、正常,利用了ListView的缓存机制,算入门,findViewById会浪费大量时间//如果为空:View未被实例化,缓存池中也无缓存,所以我们要主动为它赋一个View/*if(convertView==null){convertView=mInflater.inflate(R.layout.item,null);}ImageView imageView=(ImageView)convertView.findViewById(R.id.iv_image);TextView title=(TextView) convertView.findViewById(R.id.tv_title);TextView content=(TextView) convertView.findViewById(R.id.tv_content);//赋值ItemBean bean =mList.get(position);imageView.setImageResource(bean.ItemImageResid);title.setText(bean.ItemTitle);content.setText(bean.ItemContent);return convertView;*///方法三、建议使用ViewHolder viewHolder;if(convertView==null){viewHolder=new ViewHolder();convertView=mInflater.inflate(R.layout.item,null);//将控件保存到viewHolder中viewHolder.imageView=(ImageView)convertView.findViewById(R.id.iv_image);viewHolder.title=(TextView) convertView.findViewById(R.id.tv_title);viewHolder.content=(TextView) convertView.findViewById(R.id.tv_content);//通过setTag将ViewHoler与convertView绑定convertView.setTag(viewHolder);}else{viewHolder=(ViewHolder) convertView.getTag();}ItemBean bean =mList.get(position);viewHolder.imageView.setImageResource(bean.ItemImageResid);viewHolder.title.setText(bean.ItemTitle);viewHolder.content.setText(bean.ItemContent);return convertView;}//创建一个内部类,作业就是为了避免重复的findViewById操作class ViewHolder{//对应item.xml的三个控件public ImageView imageView;public TextView title;public TextView content;}}

这里将方法一、二都注释掉,第三种方法不仅仅利用了ListView的缓存机制,更通过ViewHolder类来实现显示数据的视图的缓存,避免了多次通过调用findViewById寻找控件
所以强烈建议使用第三种方法

ListView调用BaseAdapter适配器


第六步,在MainActivity中,我们通过setAdapter来讲view对象的数据传递到ListView对象中

MainActivity.java
package bnuz.lwj.listviewteacheing;import java.util.ArrayList;import java.util.List;import android.app.Activity;import android.os.Bundle;import android.view.Menu;import android.view.MenuItem;import android.widget.ListView;public class MainActivity extends Activity {ListView listView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);listView=(ListView) findViewById(R.id.lv_main);List<ItemBean> itemBeanList=new ArrayList<ItemBean>();for(int i=0;i<20;i++){itemBeanList.add(new ItemBean(R.drawable.ic_launcher,"我的标题"+i,"我是内容"+i));}//通过这个函数,我们可以将一个MyAdpter对象传递给我们的ListView//从而达到将数据源中多种多样的数据格式转化为ListView可以展示的格式//因为在MyAdpter中,已经将数据进行处理,赋值给View并返回过来listView.setAdapter(new MyAdapter(this,itemBeanList));}}

最后结果展示

 
总结就到此结束~~~


第一次码博客,就请各位大佬高抬贵手,本总结是看了慕课网的大佬后写的,截图也是出自视频
完整源码下载点击这里

欢迎关注我的博客,一起学习讨论
要转载,请附上原文链接,作者:SnailMann

可以关注我的私人github: https://github.com/SnailMann,欢迎watch ,star, fork
关注我的私人GitHub
虽然现在暂时没有什么东西,但是总会有的大笑


阅读全文
1 0
原创粉丝点击