Comments (13)
Hi @ronaldw
Thank you for your help.
If you'd be willing to try out this code it would be a tremendous help.
Sure I will try this
JFYI : I fond this crash more often on appcompat-v7:23.4.0 and heigher version
I have seen this issue only 2 times with appcompat-v7:23.0.1 .... not sure if that is something you want to look into
I will try your suggestion and get back to you asap
let me know how can I try your merged branch
Thank you
from recycler-view-merge-adapter.
Hi, can you please copy and past the code snippet(s) in which you instantiate the adapter, add the sub-adapters to the adapter and where you possibly notify the adapter of data changes? This would be a tremendous help.
from recycler-view-merge-adapter.
Hi Ronaldw
Thank you for response
I have simplified my code and changed it a bit, changed function and variable names and logic to a bit but code looks like this
private void updateMyAdapter() {
ModelA modelA = CManager.getInstance().getModel(mAModelID);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
if (recyclerView == null || modelA == null) {
return;
}
Activity activity = getActivity();
RecyclerViewMergeAdapter adapter = new RecyclerViewMergeAdapter();
recyclerView.setAdapter(adapter);
if (mImageHeader != null) {
// NB : mImageHeader is created onCreateView => View mImageHeader = inflater.inflate(R.layout.header_image, recyclerView, false);
adapter.addView(mImageHeader);
}
View modelHeading = null;
List<ModelB> favModelBs = CManager.getInstance().getModelBForModelA(mAModelID);
if (favModelBs != null && !favModelBs.isEmpty() && activity != null) {
MyRecyclerAdapter myRecyclerAdapter = new MyRecyclerAdapter(favModelBs, mAModelID, DisplayMode.MODEL_HINT);
myRecyclerAdapter.setItemClickListener(this);
modelHeading = inflateListLabel(recyclerView, getResources().getString(R.string.modelHeading), true); // inflateListLabel function inflate layout
adapter.addView(modelHeading);
adapter.addAdapter(myRecyclerAdapter);
}
List<String> groupingIds = modelA.getGroupingIDs();
if (groupingIds != null && !groupingIds.isEmpty()) {
for (String groupingId : groupingIds) {
GroupingModel grouping = CManager.getInstance().FetchGrouping(mAModelID, groupingId);
if (grouping != null) {
List<ModelB> modelList = grouping.getModelBList();
if (modelList != null && !modelList.isEmpty() && activity != null) {
MyRecyclerAdapter myRecyclerAdapter = new MyRecyclerAdapter(modelList, mAModelID, DisplayMode.MODEL_HINT);
myRecyclerAdapter.setItemClickListener(this);
adapter.addView(inflateListLabel(recyclerView, grouping.getName(), updatePadding));
adapter.addAdapter(myRecyclerAdapter);
}
}
}
}
adapter.notifyDataSetChanged();
}
And function call
private View inflateListLabel(ViewGroup container, String string, boolean updatePadding) {
LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View inflateView = inflater.inflate(R.layout.grouping_titles, container, false);
if (inflateView != null) {
TextView textView = (TextView) inflateView.findViewById(R.id.title_text);
if (textView != null) {
textView.setText(Html.fromHtml(string));
if (updatePadding) {
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
lp.setMargins(getResources().getDimensionPixelSize(R.dimen.marginTwo), getResources().getDimensionPixelSize(R.dimen.marginTwo), getResources().getDimensionPixelSize(R.dimen.marginTwo), getResources().getDimensionPixelSize(R.dimen.marginFour));
textView.setLayoutParams(lp);
}
}
}
return inflateView;
}
from recycler-view-merge-adapter.
Hi, @guruduttstay. The reason I am asking is because I have seen this problem occur before in my own project when I was not using the correct notify<operation>()
method or I was calling notifyDataSetChanged()
when actually my activity already had its View-s destroyed. Are you calling this method from a Fragment? If so, I would recommend always checking whether you are attached to an Activity by calling isAdded()
and making sure you are added before notifying.
Furthermore, I would recommend using notifyItemRangeInserted()
instead of notifyDataSetChanged()
. For instance when you add an adapter by calling adapter.addAdapter(mRecyclerAdapter)
you can call adapter.notifyItemRangeInserted(adapter.getItemCount() - 1 - mRecyclerAdapter.getItemCount(), adapter.getItemCount() - 1)
. This way you are informing the adapter that you have inserted some new items and using a less heavy operation than the RecyclerView having to recalculate everything.
Meanwhile, we have just merged a Pull Request that has quite drastically overhauled the source code for the adapter. If you'd be willing to try out this code it would be a tremendous help. I have been using the adapter in this way in my own project for a very long time and it works fantastically. Hope you'll fix the crash.
from recycler-view-merge-adapter.
The changes have been merged to master
just now so just pull from this repo and use the new RecyclerViewMergeAdapter
. It should be mostly backwards compatible. I personally rarely use the appcompat libraries, so I have no clue as to whether that could be a factor. I am currently just creating a simply activity and adding views to it using addView()
and then clearing them using the new call clearAdapters
. Are you using the code here or the library on bintray?
from recycler-view-merge-adapter.
Just now we have published version 2.0.0 on bintray. Use:
compile 'me.mvdw.recyclerviewmergeadapter:recyclerviewmergeadapter:2.0.0'
If you find any issues with the adapter, please file another issue. I'd be happy to help you solve any bugs if you come across them.
from recycler-view-merge-adapter.
Finally, if you are curious about how to properly use the adapter and the notify<operation>()
calls, I have just created a very small app that serves to simply test RecyclerViewMergeAdapter
's capabilities. Link: https://github.com/ronaldw/RecyclerViewMergeAdapterTest
from recycler-view-merge-adapter.
I am still getting this issue :(
from recycler-view-merge-adapter.
Hi
I have updated my code with updated RecyclerViewMergeAdapter (2.x)
and it gives better results but still in some rare cases it crashes with appCompat 23.0.1
but with appCompat 23.4.0 and higher versions still it I get this issue more often
private void updateMyAdapter() {
ModelA modelA = CManager.getInstance().getModel(mAModelID);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
if (recyclerView == null || modelA == null) {
return;
}
Activity activity = getActivity();
if (recyclerView.getAdapter() == null) {
recyclerView.setAdapter(new RecyclerViewMergeAdapter());
} else {
clearAdapters();
}
if (mImageHeader != null) {
// NB : mImageHeader is created onCreateView => View mImageHeader = inflater.inflate(R.layout.header_image, recyclerView, false);
appendView(mImageHeader);
}
View modelHeading = null;
List<ModelB> favModelBs = CManager.getInstance().getModelBForModelA(mAModelID);
if (favModelBs != null && !favModelBs.isEmpty() && activity != null) {
MyRecyclerAdapter myRecyclerAdapter = new MyRecyclerAdapter(favModelBs, mAModelID, DisplayMode.MODEL_HINT);
myRecyclerAdapter.setItemClickListener(this);
modelHeading = inflateListLabel(recyclerView, getResources().getString(R.string.modelHeading), true); // inflateListLabel function inflate layout
if (isAdded()) {
appendView(modelHeading);
myRecyclerAdapter.notifyDataSetChanged();
appendAdapter(myRecyclerAdapter);
}
}
List<String> groupingIds = modelA.getGroupingIDs();
if (groupingIds != null && !groupingIds.isEmpty()) {
for (String groupingId : groupingIds) {
GroupingModel grouping = CManager.getInstance().FetchGrouping(mAModelID, groupingId);
if (grouping != null) {
List<ModelB> modelList = grouping.getModelBList();
if (modelList != null && !modelList.isEmpty() && activity != null) {
MyRecyclerAdapter myRecyclerAdapter = new MyRecyclerAdapter(modelList, mAModelID, DisplayMode.MODEL_HINT);
myRecyclerAdapter.setItemClickListener(this);
if (isAdded()) {
appendView(inflateListLabel(recyclerView, grouping.getName(), updatePadding));
myRecyclerAdapter.notifyDataSetChanged();
appendAdapter(myRecyclerAdapter);
}
}
}
}
}
RecyclerViewMergeAdapter adapter = (RecyclerViewMergeAdapter) recyclerView.getAdapter();
if (isAdded() && adapter != null) {
adapter.notifyDataSetChanged();
}
}
private void appendAdapter(MyRecyclerAdapter myRecyclerAdapter) {
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
if (recyclerView != null) {
RecyclerViewMergeAdapter adapter = (RecyclerViewMergeAdapter) recyclerView.getAdapter();
if (adapter != null) {
adapter.addAdapter(myRecyclerAdapter);
}
}
}
private void appendView(View view) {
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
if (recyclerView != null && view != null) {
RecyclerViewMergeAdapter adapter = (RecyclerViewMergeAdapter) recyclerView.getAdapter();
if (adapter != null) {
adapter.addView(view);
}
}
}
private void clearAdapters() {
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
if (recyclerView != null && isAdded()) {
RecyclerViewMergeAdapter recyclerViewMergeAdapter = (RecyclerViewMergeAdapter) recyclerView.getAdapter();
recyclerViewMergeAdapter.clearAdapters();
int itemCountToBeCleared = recyclerViewMergeAdapter.getItemCount();
recyclerViewMergeAdapter.notifyItemRangeRemoved(0, itemCountToBeCleared);
}
}
from recycler-view-merge-adapter.
Hi @guruduttstay . Sorry that these problems keep bothering you. The RecyclerView is a rather complex component so it is not easy for me to say what is causing the exception immediately. However, I did notice in your code that you call notifyItemRangeRemoved()
with itemCountToBeCleared
set to 0
. After you call clearAdapters()
the adapter will return 0
for getItemCount()
hence you would have to call it before you clear it.
Also, when you call adapter.addView()
, make sure you call notifyItemRangeInserted()
. A single adapter is inserted when this happens, but you always have to call this method for as many items as are there are in your sub adapter. I will look into possible causes of this issue today, but I have had it myself before and it was caused by not calling the correct notify<operation>()
methods.
from recycler-view-merge-adapter.
Hi again,
To the best of my efforts I have tried to change your code to have it include the correct notify<operation>()
at the right moment:
private void updateMyAdapter() {
ModelA modelA = CManager.getInstance().getModel(mAModelID);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
if (recyclerView == null || modelA == null) {
return;
}
Activity activity = getActivity();
if (recyclerView.getAdapter() == null) {
recyclerView.setAdapter(new RecyclerViewMergeAdapter());
} else {
clearAdapters();
}
if (mImageHeader != null) {
// NB : mImageHeader is created onCreateView => View mImageHeader = inflater.inflate(R.layout.header_image, recyclerView, false);
appendView(mImageHeader);
}
View modelHeading = null;
List<ModelB> favModelBs = CManager.getInstance().getModelBForModelA(mAModelID);
if (favModelBs != null && !favModelBs.isEmpty() && activity != null) {
MyRecyclerAdapter myRecyclerAdapter = new MyRecyclerAdapter(favModelBs, mAModelID, DisplayMode.MODEL_HINT);
myRecyclerAdapter.setItemClickListener(this);
modelHeading = inflateListLabel(recyclerView, getResources().getString(R.string.modelHeading), true); // inflateListLabel function inflate layout
if (isAdded()) {
appendView(modelHeading);
myRecyclerAdapter.notifyDataSetChanged();
appendAdapter(myRecyclerAdapter);
}
}
List<String> groupingIds = modelA.getGroupingIDs();
if (groupingIds != null && !groupingIds.isEmpty()) {
for (String groupingId : groupingIds) {
GroupingModel grouping = CManager.getInstance().FetchGrouping(mAModelID, groupingId);
if (grouping != null) {
List<ModelB> modelList = grouping.getModelBList();
if (modelList != null && !modelList.isEmpty() && activity != null) {
MyRecyclerAdapter myRecyclerAdapter = new MyRecyclerAdapter(modelList, mAModelID, DisplayMode.MODEL_HINT);
myRecyclerAdapter.setItemClickListener(this);
if (isAdded()) {
appendView(inflateListLabel(recyclerView, grouping.getName(), updatePadding));
// DO NOT call notifyDataSetChanged() unless absolutely necessary!
// myRecyclerAdapter.notifyDataSetChanged();
appendAdapter(myRecyclerAdapter);
}
}
}
}
}
RecyclerViewMergeAdapter adapter = (RecyclerViewMergeAdapter) recyclerView.getAdapter();
if (isAdded() && adapter != null) {
adapter.notifyDataSetChanged();
}
}
private void appendAdapter(MyRecyclerAdapter myRecyclerAdapter) {
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
if (recyclerView != null) {
RecyclerViewMergeAdapter adapter = (RecyclerViewMergeAdapter) recyclerView.getAdapter();
if (adapter != null) {
adapter.addAdapter(myRecyclerAdapter);
adapter.notifyItemInserted(adapter.getItemCount());
}
}
}
private void appendView(View view) {
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
if (recyclerView != null && view != null) {
RecyclerViewMergeAdapter adapter = (RecyclerViewMergeAdapter) recyclerView.getAdapter();
if (adapter != null) {
adapter.addView(view);
adapter.notifyItemInserted(adapter.getItemCount());
}
}
}
private void clearAdapters() {
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
if (recyclerView != null && isAdded()) {
RecyclerViewMergeAdapter recyclerViewMergeAdapter = (RecyclerViewMergeAdapter) recyclerView.getAdapter();
int itemCountToBeCleared = recyclerViewMergeAdapter.getItemCount();
recyclerViewMergeAdapter.clearAdapters();
recyclerViewMergeAdapter.notifyItemRangeRemoved(0, itemCountToBeCleared);
}
}
I have modified your clearAdapters()
method, removed notifyDataSetChanged()
and added notifyItemRangeInserted()
to your methods appendView()
and appendAdapter()
. Could you try it out and let me know how it behaves? I have been looking around the Web and multiple sources report that the IllegalStateException
you keep encountering is due to not calling the correct notification method. Thanks and I hope you'll be able to make the merge adapter work!
from recycler-view-merge-adapter.
Thank you @ronaldw for your great help :)
Finally we figure it out and fixed it.
I am using viewPager and in next fragment I had this code where it was adding same view twice ...
and I didn't focused in that fragment at all and looking in current active tab in ViewPager and took lot of time to find actual culprit :(
View separator = Utils.inflateViewLabel(getActivity(), recyclerView ………);
if(separator != null) {
mergeAdapter.addView(separator);
mergeAdapter.addView(separator);
}
It added same view twice to mergeAdapter and ...... :(
from recycler-view-merge-adapter.
I meet the same Issue, but it does not solve my problem.Is there any answer?
from recycler-view-merge-adapter.
Related Issues (9)
- SubAdapter notifyItemMoved/notifyItemRemoved HOT 2
- error on super.onBindViewHolder
- Can not update the view added HOT 2
- RecyclerViewMergeAdapter:2.0.0 : IndexOutOfBoundsException: Inconsistency detected HOT 3
- Android RecyclerView IllegalArgumentException: called detach on an already detached child ViewHolder HOT 1
- Can we remove a particular view ( by id,view )
- Set Different Layout managers!
- How to apply ItemAnimator?
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from recycler-view-merge-adapter.