I am having a RecyclerView which is populating list of objects.Each object has one image and a comment. I want to update the comment on a specific row. I dont want to refresh the whole RecyclerView's Adapter. I just want to update or refresh that specific row. How can I achieve it? Below is my implementation. Am I doing it write ?
This method is in my Adapter: UPDATED
public void updateComment(String comment,int position){
this.mList.get(position).setCommentText(comment);
notifyItemChanged(position,this.mList);
}
From my Activity I am calling the above method like this:
adapter.updateComment("Great",1);
UPDATE:
As per the suggestion by pskink. I implemented this:
#Override
public void onBindViewHolder(CellViewHolder holder, int position, List<Object> payloads) {
if(payloads.isEmpty()){
super.onBindViewHolder(holder,position,payloads);
}else{
for (Object payload : payloads) {
if (payload instanceof MyMemo) {
holder.bindComment((MyMemo) payload);
}
}
}
}
The bindComment() method in my ViewHolder:
private void bindComment(MyMemo payload) {
comment.setText(payload.getCommentText());
}
Related
How to get the data when scrolling RecyclerView for the particular position? I have a list of items which will show the user about the upcoming events(dynamically). I need to fetch the event details when it is positioned at center, to change the position of marker. Sorry, I can't show the code. If you need more details please comment here.
You must fetch the location data inside your reyclerview adapter's onBindViewHolder.
public class Adapter extends RecyclerView.Adapter<Adapter.MyViewHolder> {
private List<Wrapper> dashboardList; //
public Adapter(List<Wrapper> dashboardList) {
this.dashboardList = dashboardList;
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
Wrapper data = dashboardList.get(position);
holder.tv_price.setText(data.getPrice());
holder.tv_address.setText(data.getAddress());
fetchLocation(data.getLocation());
}
public void fetchLocation(String location)
{
//Code for location search
}
I used notifyDataSetChanged in in my recycleriew. like this:
private void setList(List<Article> articles) {
mainList.addAll(articles);
notifyDataSetChanged();
}
But I want to use diffUtill in my recycleriew. I created my own diffUtill like this:
public class ArticleListDiffTool extends DiffUtil.Callback {
List<Article> oldList;
List<Article> newList;
private static final String TAG = "ArticleListDiffTool";
public ArticleListDiffTool(List<Article> oldList, List<Article> newList) {
this.oldList = oldList;
this.newList = newList;
Log.d(TAG, "ArticleListDiffTool: " + this.oldList.size() + "\n" + this.newList.size());
}
#Override
public int getOldListSize() {
return oldList.size();
}
#Override
public int getNewListSize() {
return newList.size();
}
#Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return oldList.get(oldItemPosition).getId() .equals( newList.get(newItemPosition).getId());
}
#Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return oldList.get(oldItemPosition).equals(newList.get(newItemPosition));
}
#Nullable
#Override
public Object getChangePayload(int oldItemPosition, int newItemPosition) {
//you can return particular field for changed item.
return super.getChangePayload(oldItemPosition, newItemPosition);
}
}
And I use it in my adapter :
private void setList(List articles) {
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new ArticleListDiffTool(this.mainList, articles),true);
mainList.addAll(articles);
diffResult.dispatchUpdatesTo(this);
}
I want to add new data to my old list. But when new data received, the recyclerView will be scrolled to the top of the list.
But I want to recyclerView be in its user state and new data add to the rest of the old list.
RecylcerView updates knows nothing about your views. When you call notifyDataSetChanged it tries to determine which views moved, or were replaced. I don't see you using setHasStableIds so when calling notifyDataSetChanged it will assume all of the content was replaced. It will jump to position 0 and be done with it. When you use setHasStableIds it will check the ids of the visible items and update the content in them. It will stop jumping around.
Now you also show that you are using DiffUtil. This is great! When you're not working with setHasStableIds this is the way to properly tell the recyclerView about what changed.
The problem you are facing is that you're using both. Either move to long ids and let the recyclerview do the diffing itself, or use DiffUtil and remove the call to notifyDataSetChanged. Either variant should work.
If you add new items at the end of the recyclerview, before you add the data, store the 1st visible item in recyclerview:
int position = ((LinearLayoutManager) recyclerView.GetLayoutManager()).findFirstVisibleItemPosition();
and after you make all the changes and call notifyDatasetChanged() scroll to position:
recyclerView.scrollToPosition(position);
I Found the problem after a few hours.
I every time that wants to update my recyclerView send received data to my adapter
And DiffUtil goes to compare my old list with received new parts and because of that (completely new items) DiffUtil decides to refresh whole recyclerView list.
Solution:
Now I get the current list from the recyclerView adapter and use addAll to insert new items that received from the server, then I pass this complete list to the adapter.
Now DiffUtil can compare diffrent between my old and new lists and recyclerView will be stay at it's current position.
I try to update just one specific item after a "basic action" (like a tap on one item) in my recycler view, but the method notifyItemChanged seems to doesn't work as expected.
Actually, the method onBindViewHolder is correctly called, and datas that I want to change in my item is correctly done. BUT, I see nothing changing in my view. I don't understand why...
My code :
- MyFragment
private void initRecyclerView() {
_recyclerView = (RecyclerView) _rootView.findViewById(R.id.recyclerView);
_recyclerView.setHasFixedSize(true);
_layoutManager = new LinearLayoutManager(getActivity());
_recyclerView.setLayoutManager(_layoutManager);
_adapter = new MyAdapter(datas, this, getContext());
_recyclerView.setAdapter(_adapter);
}
When an item is selected, I call "_adapter.update(position)" in my fragment. And so in my adapter I've this :
-Adapter
public void updateItem(int position) {
notifyItemChanged(position);
}
After this call I can see that the method OnBindViewHolder is correctly call, but nothing is changed on the view :(
EDIT : code of onBindViewHolder :
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
MyOBject object = datas.get(position);
holder.text1.setText(object.getValue1());
holder.text2.setText(object.getValue2());
if (object.getLastTimeItemClicked() != null && object.getLastTimeItemClicked().compareTo(object.getLastTimeNewContent()) > 0) {
Log.d("test", "item clicked, content changed")
holder._backgroundItem.setCardBackgroundColor(_context.getResources().getColor(bgItemRead)); // I see this log after a tap on one item, so this code is working!
}
}
EDIT 2 : I'm using tabs, maybe there is something to manage with that ?! (In each fragments linked to each tabs, there is a recycler view etc managed by a fragment)
I have a RecyclerView bound to a FirebaseRecyclerAdapter. I need to update the data displayed based on a value set by the user using Edittext and called function using button. data is only updated when i resume activity from recents.
Something like this:
public void refreshadappter(String url)
{
adapter = new FirebaseRecyclerAdapter<Home,HomeViewHolder>(
Home.class,
R.layout.home_card,
HomeViewHolder.class,
mDatabaseReference.orderByChild("name").equalTo(url)
) {
#Override
protected void populateViewHolder(HomeViewHolder viewHolder,
Home model, final int position) {
viewHolder.name.setText(model.getName());
viewHolder.religion.setText(model.getReligion());
}
};
mRecyclerView.setAdapter(adapter);
}
my RecyclerView contains Text and Delete Button when delete is clicked specific row will be deleted from ArrayList
pending.remove(p);// pending is arraylist
after this updating RecyclerView by calling this function which is inside Adapter
swap(pending);
public void swap(ArrayList<DownloadingActivity.scheduleListType> newList) {
if (pendingList != null) {
pendingList.clear();
pendingList.addAll(newList);
} else {
pendingList = newList;
}
notifyDataSetChanged();
}
but the problem is that correct item deleted successfully from ArrayList pending but on RecyclerView wrong update is displayed.
if i delete second item from array list pending but in RecyclerView updated
deleted item is last
when activity is reloaded then values in RecyclerView are showing correctly
searched lot of about it but did not found any way to solve
Instaead of using swap() to delete the item from your array list and adding them back into diffrent array list, I will suggest that you use notifyItemRemoved in your adapter. So, your adapter will look like below.
RecyclerViewAdapter.java :
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
DownloadingActivity.scheduleListType> p = pendingList.get(position);
//....
//....
holder.deleteBnt.setOnClickListner(new View.OnClickListener() {
#Override
public void onClick(View view) {
pendingList.remove(p);
notifyItemRemoved(position)
}
})
}