Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update RecyclerView Adapter Data

I am trying to figure out what is the issue with updating RecyclerView's Adapter.

After I get a new List of products, I tried to:

  1. Update the ArrayList from the fragment where recyclerView is created, set new data to adapter, and then call adapter.notifyDataSetChanged(); it did not work.

  2. Create a new adapter, as others did, and it worked for them, but there wasn't any change for me: recyclerView.setAdapter(new RecyclerViewAdapter(newArrayList))

  3. Create a method in Adapter which updates the data as follows:

     public void updateData(ArrayList<ViewModel> viewModels) {     items.clear();     items.addAll(viewModels);     notifyDataSetChanged();  } 

    Then I call this method whenever I want to update the data list; it did not work.

  4. To check if I can modify the recyclerView in any way, and I tried to remove at least an item:

      public void removeItem(int position) {      items.remove(position);      notifyItemRemoved(position);  } 

Everything remained as it was.

Here is my Adapter:

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> implements View.OnClickListener {      private ArrayList<ViewModel> items;     private OnItemClickListener onItemClickListener;      public RecyclerViewAdapter(ArrayList<ViewModel> items) {         this.items = items;     }       public void setOnItemClickListener(OnItemClickListener onItemClickListener) {         this.onItemClickListener = onItemClickListener;     }      @Override     public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {         View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycler, parent, false);         v.setOnClickListener(this);         return new ViewHolder(v);     }      public void updateData(ArrayList<ViewModel> viewModels) {         items.clear();         items.addAll(viewModels);         notifyDataSetChanged();     }     public void addItem(int position, ViewModel viewModel) {         items.add(position, viewModel);         notifyItemInserted(position);     }      public void removeItem(int position) {         items.remove(position);         notifyItemRemoved(position);     }       @Override     public void onBindViewHolder(ViewHolder holder, int position) {         ViewModel item = items.get(position);         holder.title.setText(item.getTitle());         Picasso.with(holder.image.getContext()).load(item.getImage()).into(holder.image);         holder.price.setText(item.getPrice());         holder.credit.setText(item.getCredit());         holder.description.setText(item.getDescription());          holder.itemView.setTag(item);     }       @Override     public int getItemCount() {         return items.size();     }       @Override     public void onClick(final View v) {         // Give some time to the ripple to finish the effect         if (onItemClickListener != null) {             new Handler().postDelayed(new Runnable() {                 @Override                 public void run() {                     onItemClickListener.onItemClick(v, (ViewModel) v.getTag());                 }             }, 0);         }     }      protected static class ViewHolder extends RecyclerView.ViewHolder {         public ImageView image;         public TextView price, credit, title, description;          public ViewHolder(View itemView) {             super(itemView);             image = (ImageView) itemView.findViewById(R.id.image);             price = (TextView) itemView.findViewById(R.id.price);             credit = (TextView) itemView.findViewById(R.id.credit);             title = (TextView) itemView.findViewById(R.id.title);             description = (TextView) itemView.findViewById(R.id.description);         }     }      public interface OnItemClickListener {          void onItemClick(View view, ViewModel viewModel);      } } 

And I initiate RecyclerView as follows:

recyclerView = (RecyclerView) view.findViewById(R.id.recycler); recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 5)); adapter = new RecyclerViewAdapter(items); adapter.setOnItemClickListener(this); recyclerView.setAdapter(adapter); 

So, how do I actually update adapter data in order to display newly received items?


The issue was that the layout where gridView was looked as follows:

<?xml version="1.0" encoding="utf-8"?> <LinearLayout     xmlns:android="http://schemas.android.com/apk/res/android"     android:orientation="vertical"     android:layout_width="match_parent"     android:tag="catalog_fragment"     android:layout_height="match_parent">      <FrameLayout         android:orientation="vertical"         android:layout_width="match_parent"         android:layout_height="match_parent">          <android.support.v7.widget.RecyclerView             android:id="@+id/recycler"             android:layout_width="match_parent"             android:layout_height="match_parent"             android:clipToPadding="false"/>          <ImageButton             android:id="@+id/fab"             android:layout_gravity="top|end"             style="@style/FabStyle"/>      </FrameLayout> </LinearLayout> 

Then I just removed LinearLayout and made FrameLayout as the parent layout.

like image 672
Filip Luchianenco Avatar asked Jul 12 '15 12:07

Filip Luchianenco


People also ask

How do I refresh my kotlin adapter?

To refresh the ListView in Android, call notifyDataSetChanged() method on the Adapter that has been set with the ListView.

What does notifyDataSetChanged do in RecyclerView?

notifyDataSetChanged. Notify any registered observers that the data set has changed. There are two different classes of data change events, item changes and structural changes. Item changes are when a single item has its data updated but no positional changes have occurred.


1 Answers

This is a general answer. The various ways to update the adapter data are explained. The process includes two main steps every time:

  1. Update the data set
  2. Notify the adapter of the change

Insert single item

Add "Pig" at index 2.

Insert single item
String item = "Pig"; int insertIndex = 2; data.add(insertIndex, item); adapter.notifyItemInserted(insertIndex); 

Insert multiple items

Insert three more animals at index 2.

Insert multiple items
ArrayList<String> items = new ArrayList<>(); items.add("Pig"); items.add("Chicken"); items.add("Dog"); int insertIndex = 2; data.addAll(insertIndex, items); adapter.notifyItemRangeInserted(insertIndex, items.size()); 

Remove a single item

Remove "Pig" from the list.

Remove single item
int removeIndex = 2; data.remove(removeIndex); adapter.notifyItemRemoved(removeIndex); 

Remove multiple items

Remove "Camel" and "Sheep" from the list.

Remove multiple items
int startIndex = 2; // inclusive int endIndex = 4;   // exclusive int count = endIndex - startIndex; // 2 items will be removed data.subList(startIndex, endIndex).clear(); adapter.notifyItemRangeRemoved(startIndex, count); 

Remove all items

Clear the whole list.

Remove all items
data.clear(); adapter.notifyDataSetChanged(); 

Replace old list with the new list

Clear the old list then add a new one.

Replace old list with new list
// clear old list data.clear();  // add new list ArrayList<String> newList = new ArrayList<>(); newList.add("Lion"); newList.add("Wolf"); newList.add("Bear"); data.addAll(newList);  // notify adapter adapter.notifyDataSetChanged(); 

The adapter has a reference to data, so it is important that I didn't set data to a new object. Instead, I cleared the old items from data and then added the new ones.

Update single item

Change the "Sheep" item so that it says "I like sheep."

Update single item
String newValue = "I like sheep."; int updateIndex = 3; data.set(updateIndex, newValue); adapter.notifyItemChanged(updateIndex); 

Move a single item

Move "Sheep" from position 3 to position 1.

Move single item
int fromPosition = 3; int toPosition = 1;  // update data array String item = data.get(fromPosition); data.remove(fromPosition); data.add(toPosition, item);  // notify adapter adapter.notifyItemMoved(fromPosition, toPosition); 

Code

Here is the project code for your reference. The RecyclerView Adapter code can be found at this answer.

MainActivity.java

public class MainActivity extends AppCompatActivity implements MyRecyclerViewAdapter.ItemClickListener {      List<String> data;     MyRecyclerViewAdapter adapter;      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);          // data to populate the RecyclerView with         data = new ArrayList<>();         data.add("Horse");         data.add("Cow");         data.add("Camel");         data.add("Sheep");         data.add("Goat");          // set up the RecyclerView         RecyclerView recyclerView = findViewById(R.id.rvAnimals);         LinearLayoutManager layoutManager = new LinearLayoutManager(this);         recyclerView.setLayoutManager(layoutManager);         DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),                 layoutManager.getOrientation());         recyclerView.addItemDecoration(dividerItemDecoration);         adapter = new MyRecyclerViewAdapter(this, data);         adapter.setClickListener(this);         recyclerView.setAdapter(adapter);     }      @Override     public void onItemClick(View view, int position) {         Toast.makeText(this, "You clicked " + adapter.getItem(position) + " on row number " + position, Toast.LENGTH_SHORT).show();     }      public void onButtonClick(View view) {         insertSingleItem();     }      private void insertSingleItem() {         String item = "Pig";         int insertIndex = 2;         data.add(insertIndex, item);         adapter.notifyItemInserted(insertIndex);     }      private void insertMultipleItems() {         ArrayList<String> items = new ArrayList<>();         items.add("Pig");         items.add("Chicken");         items.add("Dog");         int insertIndex = 2;         data.addAll(insertIndex, items);         adapter.notifyItemRangeInserted(insertIndex, items.size());     }      private void removeSingleItem() {         int removeIndex = 2;         data.remove(removeIndex);         adapter.notifyItemRemoved(removeIndex);     }      private void removeMultipleItems() {         int startIndex = 2; // inclusive         int endIndex = 4;   // exclusive         int count = endIndex - startIndex; // 2 items will be removed         data.subList(startIndex, endIndex).clear();         adapter.notifyItemRangeRemoved(startIndex, count);     }      private void removeAllItems() {         data.clear();         adapter.notifyDataSetChanged();     }      private void replaceOldListWithNewList() {         // clear old list         data.clear();          // add new list         ArrayList<String> newList = new ArrayList<>();         newList.add("Lion");         newList.add("Wolf");         newList.add("Bear");         data.addAll(newList);          // notify adapter         adapter.notifyDataSetChanged();     }      private void updateSingleItem() {         String newValue = "I like sheep.";         int updateIndex = 3;         data.set(updateIndex, newValue);         adapter.notifyItemChanged(updateIndex);     }      private void moveSingleItem() {         int fromPosition = 3;         int toPosition = 1;          // update data array         String item = data.get(fromPosition);         data.remove(fromPosition);         data.add(toPosition, item);          // notify adapter         adapter.notifyItemMoved(fromPosition, toPosition);     } } 

Notes

  • If you use notifyDataSetChanged(), then no animation will be performed. This can also be an expensive operation, so it is not recommended to use notifyDataSetChanged() if you are only updating a single item or a range of items.
  • Check out DiffUtil if you are making large or complex changes to a list.

Further study

  • CodePath: Using the RecyclerView
  • Smart way to update RecyclerView using DiffUtil
like image 51
Suragch Avatar answered Oct 21 '22 14:10

Suragch