I have implemented my RecyclerView
with it's Custom Adapter
as follows
Global Declarations as follows
private LinearLayoutManager linearLayoutManager;
private int pastVisibleItems, visibleItemCount, totalItemCount;
private CustomRecyclerViewAdapter customRecyclerViewAdapter;
First I created Adapter Instance inside onCreate()
method which has Empty Array
inside it and set it to recyclerView
linearLayoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(linearLayoutManager);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(
Utility.ItemDecorationConst);
recyclerView.addItemDecoration(dividerItemDecoration);
customRecyclerViewAdapter = new CustomRecyclerViewAdapter(getActivity());
recyclerView.setAdapter(customRecyclerViewAdapter);
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
visibleItemCount = linearLayoutManager.getChildCount();
totalItemCount = linearLayoutManager.getItemCount();
pastVisibleItems = linearLayoutManager.findFirstVisibleItemPosition();
if (loading) {
if ((visibleItemCount + pastVisibleItems) >= totalItemCount) {
loading = false;
customRecyclerViewAdapter.addProgressBarEntry();
controller.getNextPage(PublisherAppContainerFragment.this);
}
}
}
});
After rendering complete View when I get data from AsyncTask
for filling in recyclerView
I call following method of the Adapter
to fill data
customRecyclerViewAdapter.addAll(myArray);
note : addAll() is not any overridden method
following is code of my CustomRecyclerViewAdapter
class CustomRecyclerViewAdapter extends RecyclerView.Adapter<CustomRecyclerViewAdapter.ViewHolder> {
ArrayList<MyModel> arrayList = new ArrayList<>();
Context context;
public CustomRecyclerViewAdapter(Context context) {
this.context = context;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ViewHolder viewHolder = null;
//inflated some view
return viewHolder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
//binded data to holder
}
@Override
public int getItemCount() {
return arrayList.size();
}
public void addAll(ArrayList myArray) {
this.arrayList.addAll(myArray)
}
public void clear() {
arrayList.clear();
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public CardView cardView;
public ViewHolder(View view) {
super(view);
this.cardView = (CardView) view.findViewById(R.id.card_view);
this.cardView.setOnClickListener(this);
}
@Override
public void onClick(View view) {
//handle operations
}
}
}
So whenever I get data from AsynTask
I call method addAll()
and recyclerView
works like charm.
Now, My question is how it's working very well even though I have never called notifyDataSetChanged()
on the adapter
. Are there any previously registered Observers for the adapter? who observes if the dataset which has been returned in public int getItemCount()
has been changed?
As I have read from documentation
void notifyDataSetChanged ()
Notify any registered observers that the data set has changed.
that means even though there are some observers
registered you need to notify
them using notifyDataSetChanged()
. Right?
I also called
boolean flag = customRecyclerViewAdapter.hasObservers();
to know if there are any observers registered? Flag
is True
.
So anyone would please help me understand how exactly these things work?
If you look at the source of RecyclerView setAdapter call you will find a method setAdapterInternal(adapter, false, true);
which is responsible for
Replaces the current adapter with the new one and triggers listeners.
This method is responsible for swapping the old adapter with the new one and internally it also registers for the custom Data Observer. This is the reason you are getting the flag as true
Based on what I can see of your code, I would say that there are not any observers attached to your RecyclerView
that are picking up changes and keeping the list updated. What is more likely is that you are just getting "lucky" as when you scroll through the list the layout manager is continually calling getItemCount()
on the adapter to determine if it should show more items. Whenever you call addAll()
, you silently update the item count and it just happens to appear that observers were notified of the changes.
This is definitely a bug, and you would more likely see its effects in your implementation if you were dependent on a particular observer to monitor some aspect of the list, or doing more than just appending new items to the bottom (for example altering or inserting between existing items). The correct implementation as you pointed out is to call notifyDataSetChanged()
whenever the list is updated, or even better be more specific with what changed if you can. For example, you can use:
public void addAll(ArrayList myArray) {
int positionStart = getItemCount() - 1;
this.arrayList.addAll(myArray);
notifyItemRangeInserted(positionStart, myArray.size());
}
public void clear() {
int oldSize = getItemCount();
arrayList.clear();
notifyItemRangeRemoved(0, oldSize);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With