目录
在使用listview和recycleview之前,我们得先了解适配器的概念。
适配器
具体来说,适配器adapter是一个接口。
官方文档中是这样描述的:
an adapter object acts as a bridge between an adapterview and the underlying data for that view. the adapter provides access to the data items. the adapter is also responsible for making a android.view.view for each item in the data set.
简单来说,适配器充当着数据与视图之间交互的桥梁,将数据以合适的方式显示出来。其属于mvc模式(数据模式,控制器,视图)的一种具体情况。
mvc模式:
adapeter的继承体系:
适配器中还有许多重要的方法:
getview(int position,view convertview,viewgroup parent) :
这应该是适配器中最重要的方法了,这个方法会在每个子项被滚动到屏幕内的时候被调用,用于加载视图。
getitem(int positon):
用于获取在数据集中第position位置的实例。
该方法也会在我们设置监听器后用来简单地获取数据。
getitemid(int position)
用于获取在数据集中第position位置的实例对应的id。
不同getitem的是,某些方法(如onclicklistener的onclick方法)有id这个参数,而这个id参数就是取决于getitemid()这个返回值的。
getcount()
返回一共有几项数据。
我们主要介绍的是arrayadapter类的使用,主要通过对该类进行继承重写来实现我们自己的适配器。
listview的简单用法
1.设计一个布局以显示列表中的每一个子项
这里我简单地用一个图片 文本的形式显示一个子项,在layout下新建一个布局:
2.创建一个中间类以在适配器中加载布局,由于仅有一个图片和一个文本框,所以这里该类比较简单:
public class itemone { private int imageid; //用于存储图片的id值 private string text; //用于存储文本框要显示的内容 public itemone(string text,int imageid) { this.text = text; this.imageid = imageid; } public string gettext() { return text; } public int getimageid() { return imageid; } }
3.重点:创建自己的适配器类:
public class myadapter extends arrayadapter{ private int layoutid;//仅仅用作一个中间变量,用于将构造方法中的resoruceid(即步骤一中创建的子项布局id)传递给getview方法 public myadapter(context context, int resoruceid, list data) { super(context,resoruceid,data); //调用父类的一种构造方法 layoutid = resoruceid; } @override public view getview(int position, view convertview, viewgroup parent) { itemone itemone = getitem(position); //获取具体的中间类的实例, //这里的position其实就是itemone在具体的list或者array(构造方法中传入的list)中的索引 view view = layoutinflater.from(getcontext()).inflate(layoutid, parent,false); //此处是创建具体的子项,调用静态的layoutinflater.from()从给定的上下文中获取layoutinflater实例,再调用其inflate方法将具体的子项布局加载进来。 //inflate方法的第一个参数是子项布局的id,第二个是父布局。第三个是是否给这个view添加父布局,这里我们传入false就行了,因为一旦view有父布局,其就不能添加入listview之中了。 imageview imageview = (imageview) view.findviewbyid(r.id.image1); textview textview = (textview) view.findviewbyid(r.id.text1); //从之前加载入的子项的布局中获取具体的微件 imageview.setimageresource(itemone.getimageid()); textview.settext(itemone.gettext()); //为微件设置图片源和要显示的文本,此处要显示的内容与之前的中间类相关 return view; } }
4.在活动中具体加载和使用listview:
1.首先我们要在主布局中创建一个listview
2.在主活动中调用并加载listview :
public class mainactivity extends appcompatactivity { private arraylistmylist = new arraylist<>(); //一个数据列表,用于存储具体的数据 @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); initmyitem(); listview listview = (listview) findviewbyid(r.id.listview1); //获取listview实例 myadapter adapter = new myadapter(this,r.layout.item_layout,mylist); //创建自定义的适配器 listview.setadapter(adapter); //给listview设置适配器 } private void initmyitem()//初始化数据列表 { for(int i = 0; i < 20;i ) { itemone itemone = new itemone("item " i,r.drawable.qq1); mylist.add(itemone); } } }
这样就能具体实现一个简单的listview:
关于listview性能的优化
在上面的例子中其实listview的运行效率是很低的,因为getview()方法每次都会将布局加载一遍,一旦数据量过大就会产生卡顿。 我们可以观察getview方法的参数中有一个convertview参数,该参数用于将之前加载好的布局进行缓存。所以我们可以判断convertview参数是否为空来决定是否加载布局以提升性能:
更改适配器中的getview方法 public view getview(int position, view convertview, viewgroup parent) { itemone itemone = getitem(position); view view; if(convertview != null) { view = convertview; }else{ view = layoutinflater.from(getcontext()).inflate(layoutid, parent,false); } imageview imageview = (imageview) view.findviewbyid(r.id.image1); textview textview = (textview) view.findviewbyid(r.id.text1); imageview.setimageresource(itemone.getimageid()); textview.settext(itemone.gettext()); return view; }
既然我们能够缓存之前的view,那我们还可以借助缓存的view继续对性能进行优化。
public view getview(int position, view convertview, viewgroup parent) { itemone itemone = getitem(position); view view; viewholder viewholder = new viewholder(); if(convertview != null) { view = convertview; viewholder = (viewholder) view.gettag();//重新获取viewholder实例 }else{ view = layoutinflater.from(getcontext()).inflate(layoutid,parent,false); viewholder.imageview= (imageview) view.findviewbyid(r.id.image1); viewholder.textview = (textview) view.findviewbyid(r.id.text1); view.settag(viewholder); //将viewholder存储在view中 } viewholder.imageview.setimageresource(itemone.getimageid()); viewholder.textview.settext(itemone.gettext()); return view; } class viewholder{ imageview imageview; textview textview; } }
在这里我们自建了一个内部类viewholder用于存储具体的微件,并将其存储在view中,如果view已经被缓存过,则说明其中的微件已经绑定过,所以直接拿出来用就行了。
listview的鼠标监听事件
listview的鼠标监听事件与button的监听事件十分相似,不同的点就在于具体实现的接口,调用的方法不同:
修改oncreate方法 protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); initmyitem(); listview listview = (listview) findviewbyid(r.id.listview1); myadapter adapter = new myadapter(this,r.layout.item_layout,mylist); listview.setadapter(adapter); listview.setonitemclicklistener(new adapterview. onitemclicklistener() { @override public void onitemclick(adapterview parent, view view, int position, long id) { itemone itemone = mylist.get(position); //获取具体实例 log.d("mainactivity",itemone.gettext()); } }); }
这里简单对listview设置了一个适配器的监听器,每次点击就获取相应实例并且将其text通过日志打印出来.
recyclerview的简单用法
recyclerview的用法和listview十分相似:
1.创建具体的适配器
public class recycleadapter extends recyclerview.adapter{ private list mlist; static class viewholder extends recyclerview.viewholder{ imageview imageview; textview textview; public viewholder(view view) { super(view); imageview = (imageview) view.findviewbyid(r.id.image1); textview = (textview) view.findviewbyid(r.id.text1); } } public recycleadapter(list list) { mlist = list; } @override public viewholder oncreateviewholder(viewgroup parent,int viewtype) { view view = layoutinflater.from(parent.getcontext()) .inflate(r.layout.item_layout,parent,false); viewholder holder = new viewholder(view); return holder; } @override public void onbindviewholder(viewholder holder,int position) { itemone itemone = mlist.get(position); holder.imageview.setimageresource(itemone.getimageid()); holder.textview.settext(itemone.gettext()); } @override public int getitemcount(){ return mlist.size(); } }
我们首先新创建一个适配器类继承recyclerview.adapter。在适配器中我们创建了一个静态内部类viewholder继承recyclerview.viewhold,这个类主要是在后面的方法中使用的。
由于继承了recyclerview.adapter,该类需要重写三个方法分别用于创建viewholder,绑定viewholder和返回数据一共有多少项.
2.在主活动中配置适配器:
public class mainactivity extends appcompatactivity { private arraylistmylist = new arraylist<>(); @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); initmyitem(); recyclerview recyclerview = (recyclerview) findviewbyid(r.id.re1); linearlayoutmanager layoutmanager = new linearlayoutmanager(this); //设置线性布局管理器 recyclerview.setlayoutmanager(layoutmanager); recycleadapter adapter = new recycleadapter(mylist); recyclerview.setadapter(adapter); } private void initmyitem() { for(int i = 0; i < 20;i ) { itemone itemone = new itemone("item " i,r.drawable.qq1); mylist.add(itemone); } } }
与listview不同的可能就是recyclerview还需要额外设置布局方式,这里我们创建的是最简单的线性布局,效果与listview一样。recyclerview还有其他的布局模式,我们可以自行去体验。