java - How to access the data source of a RecyclerView adapter's ViewHolder? -
the constructor of recyclerview's adapter looks like:
context context; list<connectionitem> connections; public connectionslistadapter(context context, list connections) { this.context = context; this.connections = connections; }
after adapter's declarations, declare static viewholder class recyclerview, handles onclicks of buttons:
public static class viewholder extends recyclerview.viewholder implements view.onclicklistener { public context context; public imageview connectionimage; public textview connectionname; public imagebutton startmsg; public viewholder(view itemview, list<connectionitem> connections) { super(itemview); ... startmsg.setonclicklistener(this); } @override public void onclick(view v) { intent intent = new intent(v.getcontext(), chatactivity.class); intent.putextra("name", connections.get(getadapterposition()).getname()); // error because accessing static context intent.putextra("id", connections.get(getadapterposition()).getuid()); // error because accessing static context context.startactivity(intent); } }
the problem connections
not accessible static context in viewholder static class. what's best way viewholder information recyclerview adapter? workaround, passing data source constructor of viewholder , having new instance variable in viewholder data source:
public static class viewholder extends recyclerview.viewholder implements view.onclicklistener { public context context; public list<connectionitem> connections; public imageview connectionimage; public textview connectionname; public imagebutton startmsg; public viewholder(view itemview, list<connectionitem> connections) { super(itemview); this.connections = connections; ... startmsg.setonclicklistener(this); } @override public void onclick(view v) { intent intent = new intent(v.getcontext(), chatactivity.class); intent.putextra("name", connections.get(getadapterposition()).getname()); // okay intent.putextra("id", connections.get(getadapterposition()).getuid()); // okay context.startactivity(intent); }
does way @ break viewholder pattern or create other problems in future?
your responsibilities/concerns little scrambled.
in mvc terms, viewholder
view. it's object has references subviews findviewbyid()
doesn't have called on , over. it's still view.
however, have constructor model data argument, , has bad smell it.
the properties/variables
viewholder
should haveview
s.the thing
viewholder
constructor should ever callingfindviewbyid()
you haven't talked adapter much, you'll notice override 2 methods: oncreateviewholder
, onbindviewholder
.
within oncreateviewholder
construct viewholder
that's applicable view type. that's it. may have inflate different layouts depending on view type, dealing views here. don't pass model data viewholder
in constructor.
within onbindviewholder
, here hook view model data.
something define bind()
method viewholder
it's clear model data being handed off. bind()
method takes data , calls settext
, similar methods make views reflect model data adapter position.
but come ugly part of recyclerview
's adapter
design. there no onitemclicklistener
adapter.
google argues better design; events should handled list item view anyway. that. problem event has meet model data, , it's adapter has model data, not list item view.
and google has emphasized can't use final
on values position; need call getadapterposition()
in order index model data.
so have gone pattern accommodates these constraints.
i define
interface
event listener method takes position argument.i create instance of listener in adapter
every time bind
viewholder
pass listener instance (soviewholder
have reference listener, not adapter)on event handler in
viewholder
, callgetadapterposition()
position of list item, call listener method positionthe adapter gets listener callback, accesses correct model data , performs desired action
so here's example: have list of items have been selected, i.e. products in online shopping cart have remove button big x. have handle remove button.
define interface:
interface onitemremovedlistener { void itemremoved(int position); }
create instance of listener in adapter
private onitemremovedlistener mcallback;
set in adapter constructor:
mcallback = new onitemremovedlistener() { @override public void itemremoved(int position) { mitemlist.remove(position); notifydatasetchanged(); } };
the viewholder
subclass:
public static class productitemviewholder extends recyclerview.viewholder { private textview mproductname; private button mremovebutton; private onitemremovedlistener mlistener; public productitemviewholder(view itemview) { super(itemview); mproductname = (textview) itemview.findviewbyid(r.id.product_name); mremovebutton = (button) itemview.findviewbyid(r.id.remove_button); } public void bind(model data, onitemremovedlistener listener) { mproductname.settext(data.getproductname()); mlistener = listener; mremovebutton.setonclicklistener(new onclicklistener() { @override public void onclick(view view) { int position = getadapterposition(); if (position >= 0) { mlistener.itemremoved(position); } } }); } }
then onbindviewholder
override looks this:
@override public void onbindviewholder(productitemviewholder holder, int position) { holder.bind(mitemlist.get(position), mcallback); }
Comments
Post a Comment