android - RecyclerView not updating after adding when data was empty -
i'm facing strange problem when using recylerview inside linearlayout inside cardview. works when initial data i'm passing adapter/recyclerview not empty. when try add item dynamically (when initial data empty), adapter set's items, call's notifydatasetchanged, recyclerview stays empty.
if add data dynamically, when initial collection not empty, works perfectly. it's working on other views well. idea problem be?
thanks in advance!
the xml file:
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:card_view="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"> <data> </data> <linearlayout android:id="@+id/main_content" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v7.widget.toolbar android:id="@+id/toolbarcomposer" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorprimary" android:elevation="4dp" app:title="@string/title_timeline" app:titletextcolor="@color/white" app:navigationicon="@drawable/ic_arrow_back_black_24dp" > </android.support.v7.widget.toolbar> <android.support.v4.widget.swiperefreshlayout android:id="@+id/refreshlayout" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/intercomsdk_white"> <scrollview android:id="@+id/scrollview" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="7dp" android:background="#e1e2e4"> <linearlayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <include android:id="@+id/messagecardview" layout="@layout/item_timeline_message"/> <android.support.v7.widget.cardview android:layout_width="match_parent" android:layout_height="match_parent" card_view:cardelevation="3sp" card_view:cardusecompatpadding="true" android:layout_margintop="-10dp"> <linearlayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v7.widget.recyclerview android:id="@+id/commentrecyclerview" android:layout_width="match_parent" android:layout_height="0dp" android:background="#e1e2e4" tools:listitem="@layout/item_timeline_comment" android:layout_above="@+id/commentcontainer" android:minheight="10dp" android:layout_weight="1" /> <linearlayout android:id="@+id/commentcontainer" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:background="@color/chatwhite"> <edittext android:id="@+id/commenttextfield" android:layout_width="0dp" android:layout_height="wrap_content" android:textcolorhint="@color/chattextgray" android:textsize="14dp" android:layout_margintop="10dp" android:layout_marginleft="10dp" android:paddingbottom="15dp" android:layout_weight="0.8" android:hint="@string/commentinputhint" /> <imagebutton android:id="@+id/sendbutton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="verstuur" android:src="@drawable/ic_send_button" android:layout_gravity="center" android:layout_marginright="5dp" android:tint="@color/chatsendbuttontint" android:background="@color/chatwhite" /> </linearlayout> </linearlayout> </android.support.v7.widget.cardview> </linearlayout> </scrollview> </android.support.v4.widget.swiperefreshlayout> </linearlayout> </layout>
the activity:
public class timelinemessageactivity extends baseactivity implements timelinemessagepresenter.viewinterface { private timelinemessagepresenter presenter; private timelinecommentadapter adapter; private timelinedatamanager timelinedatamanager; private networkclientinterface timelinenetworkclient; private usersettingsstoreinterface usersettingsstore; private fragmenttimelinemessagebinding binding; private menu menu; public int messageid; private list<timelinecommentmodel> comments = new arraylist<>(); @override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); this.usersettingsstore = new usersettingsstore(getmodel().getenvironment()); this.timelinenetworkclient = new networkclient(getmodel().getenvironment(), getmodel().getcredentialstore()); this.timelinedatamanager = new timelinedatamanager(getmodel().gettimelinestore(), timelinenetworkclient); binding = databindingutil.setcontentview(this, r.layout.fragment_timeline_message); adapter = new timelinecommentadapter(new timelinecommentadapter.listener() { @override public void didclickprofileimage(timelinecommentmodel item) { } @override public void didclickmention(int userid) { presenter.didclickmention(userid); } }, getmodel()); slideinbottomanimatoradapter animatoradapter = new slideinbottomanimatoradapter(adapter, binding.commentrecyclerview); binding.commentrecyclerview.setitemanimator(new slideinoutleftitemanimator(binding.commentrecyclerview)); binding.commentrecyclerview.additemdecoration(new divideritemdecoration(this, divideritemdecoration.vertical_list)); binding.commentrecyclerview.setadapter(animatoradapter); binding.commentrecyclerview.setlayoutmanager(new linearlayoutmanager(this)); binding.refreshlayout.setonrefreshlistener(() -> presenter.refreshmessage()); binding.refreshlayout.setrefreshing(true); presenter = new timelinemessagepresenter(getmodel(), getrouter(), this.timelinedatamanager); if(getintent().getintextra("message_id", 0) > 0){ presenter.setmessageid(getintent().getintextra("message_id", 0)); } } @override public void ondestroy() { presenter = null; super.ondestroy(); } @override public void onstart() { super.onstart(); presenter.attachview(this); presenter.refreshmessage(); } @override public void onstop() { presenter.detachview(); view view = this.getcurrentfocus(); if (view != null) { inputmethodmanager imm = (inputmethodmanager)this.getsystemservice(context.input_method_service); imm.hidesoftinputfromwindow(view.getwindowtoken(), 0); } super.onstop(); } @override public void setcomments(list<timelinecommentmodel> items) { for(timelinecommentmodel model : items) { this.comments.add(model); } adapter.setitems(this.comments); binding.refreshlayout.setrefreshing(false); } @override public boolean onoptionsitemselected(menuitem item) { switch (item.getitemid()) { default: return super.onoptionsitemselected(item); } } @override public void settitle(int title){ this.getsupportactionbar().settitle(this.getstring(title)); } @override public void setedittext(string text) { binding.commenttextfield.settext(text); } @override public void setbuttonenabled(boolean enabled) { binding.sendbutton.setenabled(enabled); binding.sendbutton.setalpha((float) (enabled ? 1.0 : 0.5)); } @override public void didsendcomment() { binding.commenttextfield.settext(""); presenter.refreshmessage(); } public void setmessageid(int messageid){ this.messageid = messageid; } public void didclickmention(int userid){ getrouter().openuri(uri.parse("flexappeal://users/"+userid)); } public void didclickdeletebutton(int id){ alertdialog.builder dialog = new alertdialog.builder(this); dialog.setmessage(getstring(r.string.confirm_delete_message)); dialog.setnegativebutton(r.string.no, (dialoginterface, i) -> { dialoginterface.dismiss(); }); dialog.setpositivebutton(r.string.yes, (dialoginterface, i) -> { presenter.didclickdeletebutton(id); }); dialog.show(); } @override public void didclickbackbutton(){ this.finish(); } }
the presenter:
public class timelinemessagepresenter extends basepresenter<timelinemessagepresenter.viewinterface> { interface viewinterface extends basepresenter.viewinterface { void setcomments(list<timelinecommentmodel> items); void settitle(int title); void didsendcomment(); void setbuttonenabled(boolean enabled); void setedittext(string text); void didclickbackbutton(); } private timelineviewmodel message = new timelineviewmodel(); private list<timelinecommentmodel> comments = new arraylist<>(); private string commentmessage; private int messageid; @nonnull private final timelinedatamanager datamanager; private final boolean needsrefresh = true; public timelinemessagepresenter(@nonnull model model, @nonnull routerinterface router, @nonnull timelinedatamanager datamanager) { super(model, router); this.datamanager = datamanager; } @override protected void onattachview() { super.onattachview(); getmodel().geteventbus().register(this); updateview(); } @override protected void ondetachview() { getmodel().geteventbus().unregister(this); super.ondetachview(); } @subscribe public void onevent(socketevent event) { // todo: handle new comment in message event integrate realtime timeline } public void updateview() { if (getview() != null) { getview().setedittext(commentmessage); getview().setcomments(comments); } } private boolean shouldenablebutton() { return (commentmessage != null && commentmessage.length() > 0); } public void didclickhighfivebutton(){ datamanager.postlike(messageid).subscribe(message -> { refreshmessage(); }, error -> { log.w("timelinepresenter", error); }); } public void didclicksendcommentbutton(){ this.datamanager.postcomment(messageid, commentmessage).subscribe(result -> { getview().didsendcomment(); }, error -> { log.w("timelinepresenter", error); }); } public void refreshmessage() { datamanager.getmessagedetail(messageid).subscribe(messagedetail ->{ this.comments.clear(); this.message = createviewmodelfortimelinemessage(messagedetail); if(messagedetail.getcomments() != null){ for(comments comment : messagedetail.getcomments()) { this.comments.add(createviewmodelfortimelinecomment(comment)); } } updateview(); }, error -> { log.w("timelinemessagepresenter", error); }); } private timelinecommentmodel createviewmodelfortimelinecomment(comments c) { timelinecommentmodel vm = new timelinecommentmodel(); vm.commentid = c.getid(); vm.createdby = c.getuser(); vm.createdat = c.getcreated_at_diff(); vm.message = c.getmessage(); return vm; } public void didchangemessage(charsequence message) { this.commentmessage = message.tostring(); if (getview() != null) { getview().setbuttonenabled(shouldenablebutton()); } } public void setmessageid(int messageid){ this.messageid = messageid; } public void didclickmention(int userid){ getrouter().openuri(uri.parse("flexappeal://users/"+userid)); } public void didclickdeletebutton(int id){ datamanager.deletemessage(id).subscribe(aboolean -> { getview().didclickbackbutton(); }, error -> { getview().didclickbackbutton(); }); } }
the adapter:
class timelinecommentadapter extends bindingrecyclerviewadapter<timelinecommentmodel, itemtimelinecommentbinding> { private final listener listener; private final model model; public timelinecommentadapter(listener listener, model model) { super(r.layout.item_timeline_comment); this.listener = listener; this.model = model; } public interface listener { void didclickprofileimage(timelinecommentmodel item); void didclickmention(int userid); } @override protected void bind(itemtimelinecommentbinding binding, timelinecommentmodel item, int position) { picasso.with(binding.getroot().getcontext()).load(item.createdby.getprofileimage()).into(binding.userprofileimage); binding.userprofileimage.setonclicklistener(view -> listener.didclickprofileimage(item)); binding.userfullname.settext(item.createdby.getfullname()); binding.ago.settext(item.createdat); } @override protected void recycle(itemtimelinecommentbinding binding) { picasso.with(binding.getroot().getcontext()).cancelrequest(binding.userprofileimage); } }
the bindingrecyclerviewadapter:
public abstract class bindingrecyclerviewadapter<t, b extends viewdatabinding> extends recyclerview.adapter<bindingrecyclerviewadapter<t, b>.viewholder> { public class viewholder extends recyclerview.viewholder implements view.onclicklistener { public final b binding; public viewholder(b binding) { super(binding.getroot()); this.binding = binding; this.itemview.setonclicklistener(this); } @override public void onclick(view view) { if (onitemclicklistener != null) { int position = getadapterposition(); if (position != recyclerview.no_position) { onitemclicklistener.onitemclick(view, position); } } } } public interface onitemclicklistener { void onitemclick(view itemview, int position); } private onitemclicklistener onitemclicklistener; private list<t> items; private final int layoutres; public bindingrecyclerviewadapter(@layoutres int layoutres) { this(layoutres, null, null); } public bindingrecyclerviewadapter(@layoutres int layoutres, collection<t> items) { this(layoutres, items, null); } public bindingrecyclerviewadapter(@layoutres int layoutres, collection<t> items, onitemclicklistener onitemclicklistener) { this.layoutres = layoutres; this.items = (items == null) ? new arraylist<>() : new arraylist<>(items); this.onitemclicklistener = onitemclicklistener; } @override public viewholder oncreateviewholder(viewgroup parent, int viewtype) { b binding = databindingutil.inflate(layoutinflater.from(parent.getcontext()), layoutres, parent, false); return new viewholder(binding); } @override public void onbindviewholder(viewholder holder, int position) { t item = items.get(position); bind(holder.binding, item, position); } @override public void onviewrecycled(viewholder holder) { recycle(holder.binding); } @override public int getitemcount() { return items.size(); } protected abstract void bind(b binding, t item, int position); protected abstract void recycle(b binding); public onitemclicklistener getonitemclicklistener() { return onitemclicklistener; } public void setonitemclicklistener(onitemclicklistener onitemclicklistener) { this.onitemclicklistener = onitemclicklistener; } public list<t> getitems() { return items; } public void setitems(collection<t> items) { this.items.clear(); if (items != null) { this.items.addall(items); } notifydatasetchanged(); } }
this caused reference problem, when setting comments this: this.comments = items;
reference list
of comments added adapter
switched different list
of items (but adapter
still has reference old, empty list
).
so solve this, instead of replacing comments new list
of items, try adding items comments for-loop. loop through items , add them comments this:
for(timelinecommentmodel model: items) { this.comments.add(model); }
Comments
Post a Comment