简体   繁体   中英

Keep getting Content of the ListView has changed…error

I have revised my code multiple times to avoid this error, everytime I touch my listview adapter it is from the UI Thread. What I did was I made an async task to get the data needed for the listview. On "PostExecute" I call a static method to handle actions that need to be handled after. I get reports every now and then that the app crashes on the fragment with the ListView. It is not consistent so it is hard to reproduce but I am wondering how do I fix? Perhaps maybe I could catch the error and ask the user to refresh again but I dont think its possible. Here is my code that touches my adapter.

    public static void refresh() {
    Log.i("Handling Refresh", "Handling");
    HandleRefresh handleRefresh = new HandleRefresh(Util.tabbedActivity);

    if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB)
        handleRefresh.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
    else
        handleRefresh.execute();

}

Handle Refresh

public class HandleRefresh extends AsyncTask<String, String, String> {

Context context;
String response;
public HandleRefresh(Context context)
{
    this.context = context;
}

@Override
protected String doInBackground(String... params) {
    final LoadEvents loadEvents = new LoadEvents(Util.tabbedActivity.getApplicationContext(), 1);


    try{
        response = loadEvents.execute().get();

        Log.i("Response ", response);
        if(response.equals("A"))
        {



            Log.d("Loading Events: ", "1 Events Loaded" + " " + AdapterUtilities.posts.size());


            AdapterUtilities.sortPosts();

            Log.i("Loading Events:", " " + AdapterUtilities.posts.size());



            AdapterUtilities.ORIGINALPOSTSLISTS.addAll(AdapterUtilities.POSTSLISTS);
            AdapterUtilities.Originalposts.addAll(AdapterUtilities.posts);
            AdapterUtilities.OriginalTIMELIST.addAll(AdapterUtilities.TIMELIST);

            Calendar cal = Calendar.getInstance();
            Long realTime = cal.getTimeInMillis();

            AdapterUtilities.REALTIME = realTime;
            for (int i = 0; i < AdapterUtilities.POSTSLISTS.size(); i++) {
                Log.d("Loading Events: ", "PRE LOAD : " + AdapterUtilities.POSTSLISTS.get(i).get(AdapterUtilities.EVENTID));
            }





            Log.d("Loading Events: ", "2 Events Loaded" + " " + AdapterUtilities.posts.size());




            Util.saveToSharedPrefsInteger(Util.tabbedActivity.getApplicationContext(), "LN", 1);

            try {


            } catch (IllegalStateException ise) {
                ise.printStackTrace();
            }




        }
        else if (response.equals("D"))
        {

            return "D";
        }
        else
        {


            return "C";


        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    }
    return "C";
}


@Override
protected void onPostExecute(String o)
{
    MainFeed.setMainFeed(response);
}
}

Here is setMainFeed, the method that touches the listview and adapter. I wait for a response from the background thread then I do my actions.

    public static void setMainFeed(String response)
{



    Log.i("Handle refresh response", response);
    if(response.equals("A"))
    {
        lv.setAdapter(adapter);

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    final EventUtils EventUtils = new EventUtils(Util.tabbedActivity);

                    EventUtils.runRefresh(EventUtils.REDO_LISTS);

                    Util.tabbedActivity.runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Log.i("EVENTS TO RATE ", "EVENTS TO RATE = " + RateEventNode.EVENTS_TO_RATE);

                            if (RateEventNode.EVENTS_TO_RATE != 0) {

                                MainFeed.showRateDialog(EventUtils.EVENTSTORATELIST.get(RateEventNode.EVENTS_TO_RATE - 1));

                            }
                        }
                    });
                } catch (ExecutionException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        }).start();




        if(mainFeedLayoutsVF.getDisplayedChild() == 1) {
            mainFeedLayoutsVF.setDisplayedChild(0);
        }
        final ImageView failedRefreshButton = (ImageView) view.findViewById(R.id.failedRefreshButtonWhite);
        failedRefreshButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                actionRefresh.setActionView(abprogress);
                failedRefreshButton.setVisibility(View.INVISIBLE);
                refresh();
            }
        });






        swipeLayout.setRefreshing(false);



        EventUtils.enableServicesAndReceivers(Util.tabbedActivity);



        Log.i("LV ", "LV  " + lv.getAdapter().toString());

        if(actionRefresh != null) {
            actionRefresh.setActionView(null);
        }








    }
    else if(response.equals("D"))
    {

        if(mainFeedLayoutsVF.getDisplayedChild() == 0) {
            mainFeedLayoutsVF.setDisplayedChild(1);
        }

        if(actionRefresh != null) {
            actionRefresh.setActionView(null);
        }
        final ImageView failedRefreshButton = (ImageView) view.findViewById(R.id.failedRefreshButtonWhite);
        failedRefreshButton.setVisibility(View.INVISIBLE);

        failedRefreshTV.setText("Whoops! Looks like you aren't following anyone. Go to the DISCOVER tab to get connected.");


        failedRefreshButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                actionRefresh.setActionView(abprogress);
                failedRefreshButton.setVisibility(View.INVISIBLE);
                refresh();
            }
        });
    }
    else
    {

        if(mainFeedLayoutsVF.getDisplayedChild() == 0) {
            mainFeedLayoutsVF.setDisplayedChild(1);
        }

        if(actionRefresh != null) {
            actionRefresh.setActionView(null);
        }

        final ImageView failedRefreshButton = (ImageView) view.findViewById(R.id.failedRefreshButtonWhite);
        failedRefreshButton.setVisibility(View.VISIBLE);

        failedRefreshTV.setText(Util.tabbedActivity.getString(R.string.couldNotConnect));

        failedRefreshButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                actionRefresh.setActionView(abprogress);
                failedRefreshButton.setVisibility(View.INVISIBLE);
                refresh();
            }
        });

    }
}

Here is the LogCat

01-23 09:47:56.283  18567-18567/com.android.wallfly E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.android.wallfly, PID: 18567
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(2131362088, class android.widget.ListView) with Adapter(class android.widget.HeaderViewListAdapter)]
        at android.widget.ListView.layoutChildren(ListView.java:1566)
        at android.widget.AbsListView.onLayout(AbsListView.java:2528)
        at android.view.View.layout(View.java:15655)
        at android.view.ViewGroup.layout(ViewGroup.java:4856)
        at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1055)
        at android.view.View.layout(View.java:15655)
        at android.view.ViewGroup.layout(ViewGroup.java:4856)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
        at android.view.View.layout(View.java:15655)
        at android.view.ViewGroup.layout(ViewGroup.java:4856)
        at android.support.v4.widget.SwipeRefreshLayout.onLayout(SwipeRefreshLayout.java:543)
        at android.view.View.layout(View.java:15655)
        at android.view.ViewGroup.layout(ViewGroup.java:4856)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
        at android.view.View.layout(View.java:15655)
        at android.view.ViewGroup.layout(ViewGroup.java:4856)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
        at android.view.View.layout(View.java:15655)
        at android.view.ViewGroup.layout(ViewGroup.java:4856)
        at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1677)
        at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1531)
        at android.widget.LinearLayout.onLayout(LinearLayout.java:1440)
        at android.view.View.layout(View.java:15655)
        at android.view.ViewGroup.layout(ViewGroup.java:4856)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
        at android.view.View.layout(View.java:15655)
        at android.view.ViewGroup.layout(ViewGroup.java:4856)
        at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1055)
        at android.view.View.layout(View.java:15655)
        at android.view.ViewGroup.layout(ViewGroup.java:4856)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
        at android.view.View.layout(View.java:15655)
        at android.view.ViewGroup.layout(ViewGroup.java:4856)
        at com.android.internal.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:438)
        at android.view.View.layout(View.java:15655)
        at android.view.ViewGroup.layout(ViewGroup.java:4856)
        at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
        at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
        at android.view.View.layout(View.java:15655)
        at android.view.ViewGroup.layout(ViewGroup.java:4856)
        at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2282)
        at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2002)
        at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1234)
        at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6465)
        at android.view.Choreographer$CallbackRecord.run(Choreographer.java:803)
        at android.view.Choreographer.doCallbacks(Choreographer.java:603)
        at android.view.Choreographer.doFrame(Choreographer.java:573)
        at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:789)
        at android.os.Handler.handleCallback(Handler.java:733)
        at android.os.Handler.dispatchMessage(Handler.java:95)
        at android.os.Looper.loop(Looper.java:157)
        at android.app.ActivityThread.main(ActivityThread.java:5356)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.Zygot

What am I doing wrong?

If you happen to change the underlying data that feeds into your adapter which I suspect you may be doing with

AdapterUtilities.ORIGINALPOSTSLISTS.addAll(AdapterUtilities.POSTSLISTS); 
AdapterUtilities.Originalposts.addAll(AdapterUtilities.posts);   
AdapterUtilities.OriginalTIMELIST.addAll(AdapterUtilities.TIMELIST);

whenever you change data that is displayed in your adapter you have to call notifyDatasetChanged() see the base adapter docs

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM