Android, ListView IllegalStateException: “The content of the adapter has changed but ListView did not receive a notification”

后端 未结 25 2059
执念已碎
执念已碎 2020-11-22 16:59

What I want to do: run a background thread which calculates ListView contents and update ListView partially, while results are calculated.

W

25条回答
  •  有刺的猬
    2020-11-22 17:51

    This is a MultiThreading Issue and Using Properly Synchronized Blocks This can be prevented. Without putting extra things on UI Thread and causing loss of responsiveness of app.

    I also faced the same. And as the most accepted answer suggests making change to adapter data from UI Thread can solve the issue. That will work but is a quick and easy solution but not the best one.

    As you can see for a normal case. Updating data adapter from background thread and calling notifyDataSetChanged in UI thread works.

    This illegalStateException arises when a ui thread is updating the view and another background thread changes the data again. That moment causes this issue.

    So if you will synchronize all the code which is changing the adapter data and making notifydatasetchange call. This issue should be gone. As gone for me and i am still updating the data from background thread.

    Here is my case specific code for others to refer.

    My loader on the main screen loads the phone book contacts into my data sources in the background.

        @Override
        public Void loadInBackground() {
            Log.v(TAG, "Init loadings contacts");
            synchronized (SingleTonProvider.getInstance()) {
                PhoneBookManager.preparePhoneBookContacts(getContext());
            }
        }
    

    This PhoneBookManager.getPhoneBookContacts reads contact from phonebook and fills them in the hashmaps. Which is directly usable for List Adapters to draw list.

    There is a button on my screen. That opens a activity where these phone numbers are listed. If i directly setAdapter over the list before the previous thread finishes its work which is fast naviagtion case happens less often. It pops up the exception .Which is title of this SO question. So i have to do something like this in the second activity.

    My loader in the second activity waits for first thread to complete. Till it shows a progress bar. Check the loadInBackground of both the loaders.

    Then it creates the adapter and deliver it to the activity where on ui thread i call setAdapter.

    That solved my issue.

    This code is a snippet only. You need to change it to compile well for you.

    @Override
    public Loader onCreateLoader(int arg0, Bundle arg1) {
        return new PhoneBookContactLoader(this);
    }
    
    @Override
    public void onLoadFinished(Loader arg0, PhoneBookContactAdapter arg1) {
        contactList.setAdapter(adapter = arg1);
    }
    
    /*
     * AsyncLoader to load phonebook and notify the list once done.
     */
    private static class PhoneBookContactLoader extends AsyncTaskLoader {
    
        private PhoneBookContactAdapter adapter;
    
        public PhoneBookContactLoader(Context context) {
            super(context);
        }
    
        @Override
        public PhoneBookContactAdapter loadInBackground() {
            synchronized (SingleTonProvider.getInstance()) {
                return adapter = new PhoneBookContactAdapter(getContext());    
            }
        }
    
    }
    

    Hope this helps

提交回复
热议问题