'java.lang.IllegalStateException:Make sure the content of your adapter is not modified from a background thread, but only from the UI thread
java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(2131296513, class xyz.ScrollDetectableListView) with Adapter(class android.widget.HeaderViewListAdapter)]
I am getting above exception sometimes while scrolling through the dynamic listview and then clicking on item.I researched a lot but unable to find the exact reason that why i am getting this error sometimes and how it can be resolved?
private ScrollDetectableListView mFListView;
public FAdapter mFAdapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_feed_view, container, false);
View headerView = getActivity().getLayoutInflater().inflate(R.layout.view_feed_header, null);
try{
mFListView = (ScrollDetectableListView) rootView.findViewById(R.id.feed_list_view);
mFContainer = (SwipeRefreshLayout) rootView.findViewById(R.id.feed_container);
mFListView.addHeaderView(headerView);
mFListView.setEmptyView(rootView.findViewById(R.id.empty_view));
mFContainer.setColorSchemeResources(R.color.green, R.color.pink, R.color.fbcolor,
R.color.instagramcolor, R.color.googlecolor, R.color.flickrcolor);
mFView = getActivity().getLayoutInflater().inflate(R.layout.view_footer, null);
ImageView rotateImageView = (ImageView) mFooterView.findViewById(R.id.spinner);
Animation rotation = AnimationUtils.loadAnimation(getActivity(), R.anim.rotate);
rotation.setFillAfter(false);
rotateImageView.startAnimation(rotation);
mFContainer.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh()
{
initializeFListView();
}
});
initializeFListView();
mProgressDialog.setVisibility(View.VISIBLE);
mHActivity.setDataChangedListener(new DataChangedListener() {
@Override
public void onDataChanged() {
mFContainer.setRefreshing(true);
mProgressDialog.setVisibility(View.GONE);
initializeFListView();
}
});
}catch(Exception e){}
return rootView;
}
public void initializeFListView()
{
FApi.getTrending(getActivity(), xyz, new APIResponseListener() {
@Override
public void onResponse(Object response) {
setFeedAdapter((List<Video>) response);
}
@Override
public void onError(VolleyError error) {
if (error instanceof NoConnectionError) {
String errormsg = getResources().getString(R.string.no_internet_error_msg);
Toast.makeText(getActivity(), errormsg, Toast.LENGTH_LONG).show();
}
}
});
}
private void setFAdapter(List<Video> response)
{try {
List<Video> videos = response;
mFAdapter = new FAdapter(getActivity(), videos, mProfileClickListener, mCommentClickListener);
mFListView.setOnScrollListener(new EndlessScrollListenerFeedView(getActivity(), mFListView, mFView, mFAdapter, videos, mFType, ""));
mFListView.setAdapter(mFAdapter);
mProgressDialog.setVisibility(View.GONE);
if (mFContainer.isRefreshing()) {
mFContainer.setRefreshing(false);
}
if (mFAdapter.getCount() < mCount) {
mFView.setVisibility(View.GONE);
mFListView.removeFooterView(mFooterView);
}
}catch(Exception e){}
}
}
Solution 1:[1]
My suggestion try to set ur list adapter on UI Thread,,,
private void setFAdapter(List<Video> response)
{
try {
List<Video> videos = response;
mFAdapter = new FAdapter(getActivity(), videos, mProfileClickListener, mCommentClickListener);
mFListView.setOnScrollListener(new EndlessScrollListenerFeedView(getActivity(), mFListView, mFView, mFAdapter, videos, mFType, ""));
runOnUiThread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
mFListView.setAdapter(mFAdapter);
}
});
mProgressDialog.setVisibility(View.GONE);
if (mFContainer.isRefreshing()) {
mFContainer.setRefreshing(false);
}
if (mFAdapter.getCount() < mCount) {
mFView.setVisibility(View.GONE);
mFListView.removeFooterView(mFooterView);
}
}catch(Exception e){}
}
}
Solution 2:[2]
Keep one singleton class object in hand. So that you can synchronize two thread on it. Care to be taken to not to block the ui thread.
Reduce number of interfaces to only one method to start preparing data for your list and only one method to call your notifydatasetchanged/setAdapter on list.
Means there should be only one method like prepareData() which will be executed by a background thread. synchronise this method on your singleton object.
MyListAdaper adapter = null;
// Call this from a background thread
public void prepareData() {
synchronized (SingleTonProvider.getInstance()) {
List<AnyDataTypeYouWant> data = null;
// populate data here by your application logic.
adapter = new MyListAdaper(data);
}
}
And have only one method to refresh list.
// Also Call this from a background thread only
public void refreshList() {
synchronized (SingleTonProvider.getInstance()) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mFListView.setAdapter(adapter);
}
});
}
}
- have no other code on any place to prepare data and set data on list.
- Call the methods I mentioned from a background thread only.
I just gave general solution to your problem. You have to work on your specific case by yourself.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | halfer |