IT

Android, ListView IllegalStateException :“어댑터의 내용이 변경되었지만 ListView가 알림을받지 못했습니다”

lottoking 2020. 5. 16. 10:29
반응형

Android, ListView IllegalStateException :“어댑터의 내용이 변경되었지만 ListView가 알림을받지 못했습니다”


내가하고 싶은 일 : 결과가 계산되는 동안 ListView 내용을 계산하고 ListView를 부분적으로 업데이트하는 백그라운드 스레드를 실행하십시오.

내가 피해야 할 것 : 백그라운드 스레드에서 ListAdapter 내용을 망칠 수 없으므로 AsyncTask를 상속하고 onProgressUpdate에서 결과를 어댑터에 추가합니다. 내 어댑터는 결과 객체의 ArrayList를 사용하며 해당 어레이 목록의 모든 작업이 동기화됩니다.

다른 사람들의 연구 : 여기에는 매우 귀중한 자료가 있습니다 . 또한 ~ 500 명의 사용자 그룹에 대해 거의 매일 충돌이 발생 list.setVisibility(GONE)/trackList.setVisibility(VISIBLE)했으며 onProgressUpdate 블록을 추가 하면 충돌이 10 배 감소했지만 사라지지 않았습니다. ( 답변 으로 제안되었습니다 )

내가 때때로 얻는 것 : 실제로는 거의 발생하지 않습니다 (3.5k 사용자 중 한 주에 한 번). 그러나이 버그를 완전히 제거하고 싶습니다. 부분 스택 추적은 다음과 같습니다.

`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. [in ListView(2131296334, class android.widget.ListView) with Adapter(class com.transportoid.Tracks.TrackListAdapter)]
at android.widget.ListView.layoutChildren(ListView.java:1432)
at android.widget.AbsListView.onTouchEvent(AbsListView.java:2062)
at android.widget.ListView.onTouchEvent(ListView.java:3234)
at android.view.View.dispatchTouchEvent(View.java:3709)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:852)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:884)
[...]

도움? 더 이상 필요하지 않습니다. 아래를 참조하십시오.

최종 답변 : 결과적으로 notifyDataSetChanged깜박임과 급격한 목록 변경을 피하기 위해 5 회 삽입 할 때마다 전화 를 걸었습니다. 기본 목록이 변경되면 항상 어댑터에 알리십시오. 이 버그는 오래 전에 사라졌습니다.


나는 같은 문제가 있었다.

ArrayListUI 스레드 외부에 항목을 추가하고있었습니다 .

솔루션 : 두 가지를 모두 수행 했으며 UI 스레드에서 adding the items호출 notifyDataSetChanged()했습니다.


같은 문제가 있었지만 방법을 사용하여 문제를 해결했습니다.

requestLayout();

수업에서 ListView


이것은 멀티 스레딩 문제이며 제대로 동기화 된 블록 사용 방지 할 수 있습니다. UI 스레드에 추가 항목을 넣지 않고 앱의 응답 성을 잃지 않습니다.

나도 똑같이 직면했다. 가장 널리 인정되는 답변에서 UI Thread에서 어댑터 데이터를 변경하면 문제를 해결할 수 있습니다. 그것은 작동하지만 빠르고 쉬운 해결책이지만 최선의 해결책은 아닙니다.

보시다시피 정상적인 경우입니다. 백그라운드 스레드에서 데이터 어댑터를 업데이트하고 UI 스레드에서 notifyDataSetChanged를 호출하면 작동합니다.

이 illegalStateException은 UI 스레드가보기를 업데이트하고 다른 백그라운드 스레드가 데이터를 다시 변경하는 경우 발생합니다. 그 순간이 문제가 발생합니다.

따라서 어댑터 데이터를 변경하고 notifydatasetchange를 호출하는 모든 코드를 동기화하는 경우. 이 문제는 사라져야합니다. 나를 위해 사라졌고 여전히 백그라운드 스레드에서 데이터를 업데이트하고 있습니다.

다른 사람들이 참조 할 수있는 사례 별 코드는 다음과 같습니다.

메인 화면의 내 로더는 전화 번호부 연락처를 백그라운드의 내 데이터 소스에로드합니다.

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

이 PhoneBookManager.getPhoneBookContacts는 전화 번호부에서 연락처를 읽고 해시 맵에 채 웁니다. 목록 어댑터가 목록을 그리는 데 직접 사용할 수 있습니다.

화면에 버튼이 있습니다. 전화 번호가 나열된 활동이 열립니다. 이전 스레드가 작업을 완료하기 전에 목록에 어댑터를 직접 설정하면 빠른 탐색 사례가 덜 자주 발생합니다. 이 SO 질문의 제목은 예외입니다. 두 번째 활동에서 이와 같은 작업을 수행해야합니다.

두 번째 활동의 내 로더는 첫 번째 스레드가 완료되기를 기다립니다. 진행률 표시 줄이 표시 될 때까지 두 로더의 loadInBackground를 확인하십시오.

그런 다음 어댑터를 만들고 UI 스레드에서 setAdapter를 호출하는 활동으로 전달합니다.

내 문제가 해결되었습니다.

이 코드는 스 니펫 전용입니다. 컴파일이 잘되도록 변경해야합니다.

@Override
public Loader<PhoneBookContactAdapter> onCreateLoader(int arg0, Bundle arg1) {
    return new PhoneBookContactLoader(this);
}

@Override
public void onLoadFinished(Loader<PhoneBookContactAdapter> arg0, PhoneBookContactAdapter arg1) {
    contactList.setAdapter(adapter = arg1);
}

/*
 * AsyncLoader to load phonebook and notify the list once done.
 */
private static class PhoneBookContactLoader extends AsyncTaskLoader<PhoneBookContactAdapter> {

    private PhoneBookContactAdapter adapter;

    public PhoneBookContactLoader(Context context) {
        super(context);
    }

    @Override
    public PhoneBookContactAdapter loadInBackground() {
        synchronized (SingleTonProvider.getInstance()) {
            return adapter = new PhoneBookContactAdapter(getContext());    
        }
    }

}

도움이 되었기를 바랍니다


나는 2 개의 목록을 가지고 이것을 해결했다. 하나는 어댑터에만 사용하고 다른 목록에서는 모든 데이터 변경 / 업데이트를 수행합니다. 이를 통해 백그라운드 스레드의 한 목록에서 업데이트를 수행 한 다음 기본 / UI 스레드에서 "어댑터"목록을 업데이트 할 수 있습니다.

List<> data = new ArrayList<>();
List<> adapterData = new ArrayList();

...
adapter = new Adapter(adapterData);
listView.setAdapter(adapter);

// Whenever data needs to be updated, it can be done in a separate thread
void updateDataAsync()
{
    new Thread(new Runnable()
    {
        @Override
        public void run()
        {
            // Make updates the "data" list.
            ...

            // Update your adapter.
            refreshList();
        }
    }).start();
}

void refreshList()
{
    runOnUiThread(new Runnable()
    {
        @Override
        public void run()
        {
            adapterData.clear();
            adapterData.addAll(data);
            adapter.notifyDataSetChanged();
            listView.invalidateViews();
        }
    });
}

이 코드를 작성하여 ~ 12 시간 동안 2.1 에뮬레이터 이미지에서 실행했으며 IllegalStateException을 얻지 못했습니다. 나는 안드로이드 프레임 워크에 이것에 대한 의심의 이점을 줄 것이고 그것이 코드에 오류가 있다고 말할 것입니다. 이게 도움이 되길 바란다. 목록과 데이터에 적용 할 수 있습니다.

public class ListViewStressTest extends ListActivity {
    ArrayAdapter<String> adapter;
    ListView list;
    AsyncTask<Void, String, Void> task;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        this.adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
        this.list = this.getListView();

        this.list.setAdapter(this.adapter);

        this.task = new AsyncTask<Void, String, Void>() {
            Random r = new Random();
            int[] delete;
            volatile boolean scroll = false;

            @Override
            protected void onProgressUpdate(String... values) {
                if(scroll) {
                    scroll = false;
                    doScroll();
                    return;
                }

                if(values == null) {
                    doDelete();
                    return;
                }

                doUpdate(values);

                if(ListViewStressTest.this.adapter.getCount() > 5000) {
                    ListViewStressTest.this.adapter.clear();
                }
            }

            private void doScroll() {
                if(ListViewStressTest.this.adapter.getCount() == 0) {
                    return;
                }

                int n = r.nextInt(ListViewStressTest.this.adapter.getCount());
                ListViewStressTest.this.list.setSelection(n);
            }

            private void doDelete() {
                int[] d;
                synchronized(this) {
                    d = this.delete;
                }
                if(d == null) {
                    return;
                }
                for(int i = 0 ; i < d.length ; i++) {
                    int index = d[i];
                    if(index >= 0 && index < ListViewStressTest.this.adapter.getCount()) {
                        ListViewStressTest.this.adapter.remove(ListViewStressTest.this.adapter.getItem(index));
                    }
                }
            }

            private void doUpdate(String... values) {
                for(int i = 0 ; i < values.length ; i++) {
                    ListViewStressTest.this.adapter.add(values[i]);
                }
            }

            private void updateList() {
                int number = r.nextInt(30) + 1;
                String[] strings = new String[number];

                for(int i = 0 ; i < number ; i++) {
                    strings[i] = Long.toString(r.nextLong());
                }

                this.publishProgress(strings);
            }

            private void deleteFromList() {
                int number = r.nextInt(20) + 1;
                int[] toDelete = new int[number];

                for(int i = 0 ; i < number ; i++) {
                    int num = ListViewStressTest.this.adapter.getCount();
                    if(num < 2) {
                        break;
                    }
                    toDelete[i] = r.nextInt(num);
                }

                synchronized(this) {
                    this.delete = toDelete;
                }

                this.publishProgress(null);
            }

            private void scrollSomewhere() {
                this.scroll = true;
                this.publishProgress(null);
            }

            @Override
            protected Void doInBackground(Void... params) {
                while(true) {
                    int what = r.nextInt(3);

                    switch(what) {
                        case 0:
                            updateList();
                            break;
                        case 1:
                            deleteFromList();
                            break;
                        case 2:
                            scrollSomewhere();
                            break;
                    }

                    try {
                        Thread.sleep(0);
                    } catch(InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }

        };

        this.task.execute(null);
    }
}

이것이 간헐적으로 발생했다면 마지막 항목을 클릭 한 후 목록을 스크롤했을 때만이 문제가 발생했습니다. 목록이 스크롤되지 않으면 모든 것이 잘 작동합니다.

MUCH 디버깅 후 버그가 발생했지만 Android 코드에서도 일관성이 없습니다.

유효성 검사가 수행되면이 코드는 ListView에서 실행됩니다.

        } else if (mItemCount != mAdapter.getCount()) {
            throw new IllegalStateException("The content of the adapter has changed but "
                    + "ListView did not receive a notification. Make sure the content of "

그러나 onChange가 발생하면 AdapterView (ListView의 부모) 에서이 코드를 시작합니다.

    @Override
    public void onChanged() {
        mDataChanged = true;
        mOldItemCount = mItemCount;
        mItemCount = getAdapter().getCount();

어댑터가 동일하다는 보장은 없습니다.

필자의 경우 'LoadMoreAdapter'이므로 getAdapter 호출에서 WrappedAdapter를 반환했습니다 (기본 객체에 액세스하기 위해). 그 결과 여분의 '추가로드'항목과 예외가 발생하여 개수가 달라졌습니다.

나는 문서가 그것을 좋아하는 것처럼 보이기 때문에 이것을했다.

ListView.getAdapter javadoc

이 ListView에서 현재 사용중인 어댑터를 반환합니다. 리턴 된 어댑터는 setAdapter (ListAdapter)에 전달 된 것과 동일한 어댑터는 아니지만 WrapperListAdapter 일 수 있습니다.


내 문제는 ListView와 함께 필터를 사용하는 것과 관련이 있습니다 .

ListView의 기본 데이터 모델을 설정하거나 업데이트 할 때 다음과 같이했습니다.

public void updateUnderlyingContacts(List<Contact> newContacts, String filter)
{
    this.allContacts = newContacts;
    this.filteredContacts = newContacts;
    getFilter().filter(filter);
}

filter()마지막 줄에서 호출 notifyDataSetChanged()하면 필터의 publishResults()메소드 에서 호출 되어야합니다 . 때로는 빠른 Nexus 5에서 제대로 작동 할 수도 있지만 실제로는 느린 기기 나 리소스 집약적 환경에서 발견되는 버그가 숨겨져 있습니다.

문제는 필터링이 비동기 적으로 수행되므로 filter()명령문 의 끝 과에 대한 호출 사이 publishResults()에 UI 스레드에서 일부 다른 UI 스레드 코드가 실행되어 어댑터의 내용을 변경할 수 있다는 것입니다.

실제 수정은 쉽습니다 notifyDataSetChanged(). 필터링을 요청하기 전에 호출 하기 만하면됩니다 .

public void updateUnderlyingContacts(List<Contact> newContacts, String filter)
{
    this.allContacts = newContacts;
    this.filteredContacts = newContacts;
    notifyDataSetChanged(); // Fix
    getFilter().filter(filter);
}

Feed 객체 인 경우 List가 있습니다. none-UI 스레드에서 추가되고 잘립니다. 아래 어댑터와 잘 작동합니다. FeedAdapter.notifyDataSetChanged어쨌든 조금 후에 UI 스레드를 호출 합니다. UI가 죽었을 때도 Feed 객체가 로컬 서비스의 메모리에 남아 있기 때문에 이것을 좋아합니다.

public class FeedAdapter extends BaseAdapter {
    private int size = 0;
    private final List<Feed> objects;

    public FeedAdapter(Activity context, List<Feed> objects) {
        this.context = context;
        this.objects = objects;
        size = objects.size();
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ...
    }

    @Override
    public void notifyDataSetChanged() {
        size = objects.size();

        super.notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        return size;
    }

    @Override
    public Object getItem(int position) {
        try {
            return objects.get(position);
        } catch (Error e) {
            return Feed.emptyFeed;
        }
    }

    @Override
    public long getItemId(int position) {
        return position;
    }
}


며칠 전에 동일한 문제가 발생하여 하루에 수천 건의 충돌이 발생했으며 약 0.1 %의 사용자가이 상황을 충족합니다. 나는 시도 setVisibility(GONE/VISIBLE)하고 requestLayout()있지만, 충돌 횟수는 약간 감소합니다.

그리고 마침내 그것을 해결했습니다. 와 함께하는 것은 없습니다 setVisibility(GONE/VISIBLE). 와 함께하는 것은 없습니다 requestLayout().

마지막으로 데이터를 업데이트 한 후 Handler호출 하는 데 사용 된 이유는 notifyDataSetChanged()다음과 같습니다.

  1. 데이터를 모델 객체로 업데이트합니다 (데이터 소스라고 함).
  2. 사용자가 listview를 터치합니다 ( checkForTap()/ onTouchEvent()를 호출하고 마지막으로 호출 할 수 있음 layoutChildren())
  3. 어댑터는 모델 오브젝트에서 데이터를 가져오고 notifyDataSetChanged()뷰를 호출 하고 업데이트합니다.

그리고 나는 또 다른 실수를 getCount(), getItem()그리고 getView()내가 직접 오히려 어댑터 사본 그들을보다, 데이터 소스의 필드를 사용합니다. 따라서 다음과 같은 경우에 충돌이 발생합니다.

  1. 어댑터는 마지막 응답이 제공하는 데이터를 업데이트합니다
  2. 다음에 응답 할 때 DataSource는 데이터를 업데이트하여 항목 수를 변경합니다.
  3. 사용자가 탭 또는 이동 또는 뒤집기 일 수있는 목록보기를 터치합니다.
  4. getCount()그리고 getView()라고하며, 목록보기 발견 데이터가 일치하지 않습니다, 그리고 같은 예외가 발생합니다 java.lang.IllegalStateException: The content of the adapter has changed but.... 다른 일반적인 예외는에서 IndexOutOfBoundException헤더 / 바닥 글을 사용 하는 경우입니다 ListView.

그래서 해결책은 쉽습니다. 내 핸들러가 데이터를 가져오고 호출하기 위해 어댑터를 트리거 할 때 데이터 소스에서 어댑터로 데이터를 복사합니다 notifyDataSetChanged(). 이제 충돌이 다시 발생하지 않습니다.


정확히 동일한 오류 로그로 동일한 문제에 직면했습니다. 필자의 경우 onProgress()AsyncTask는을 사용하여 값을 어댑터에 추가합니다 mAdapter.add(newEntry). UI의 응답 성이 떨어지는 것을 피하기 위해 초를 4 번 설정 mAdapter.setNotifyOnChange(false)하고 호출했습니다 mAdapter.notifyDataSetChanged(). 초당 한 번 배열이 정렬됩니다.

이것은 잘 작동하고 매우 중독성으로 보이지만 불행히도 표시된 목록 항목을 자주 터치하면 충돌이 발생할 수 있습니다.

그러나 수용 가능한 해결 방법을 찾은 것 같습니다. 내 생각에 UI 스레드에서만 작업하더라도 어댑터가 호출하지 않고 데이터의 많은 변경 사항을 수락하지 않는다고 notifyDataSetChanged()생각합니다.이 때문에 언급 된 300ms가 끝날 때까지 모든 새 항목을 저장하는 대기열을 만들었습니다. 이 순간에 도달하면 저장된 모든 항목을 한 번에 추가하고을 호출 notifyDataSetChanged()합니다. 지금까지 나는 더 이상 목록을 추락 할 수 없었다 .


이것은 Android 4 ~ 4.4 (KitKat)에서 알려진 버그이며 "> 4.4"에서 해결되었습니다.

여기를 참조하십시오 : https://code.google.com/p/android/issues/detail?id=71936


내 XMPP 알림 응용 프로그램에서 동일한 문제에 직면하더라도 수신자 메시지를 목록보기에 다시 추가해야합니다 (으로 구현 ArrayList). 수신자 콘텐츠를 MessageListener별도의 스레드를 통해 추가하려고하면 응용 프로그램이 위의 오류로 종료됩니다. Activity 클래스의 일부인 arraylist& setListviewadapater통해 runOnUiThread메소드에 내용을 추가 하여이 문제를 해결했습니다 . 이것은 내 문제를 해결했습니다.


나는 비슷한 문제에 직면했다. 내 경우에 내가 해결 한 방법은 다음과 같다. task이미 있는지 RUNNING또는 FINISHED작업을 한 번만 실행할 수 있는지 확인합니다 . 아래에는 내 솔루션의 일부 및 적응 코드가 표시됩니다.

public class MyActivity... {
    private MyTask task;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
       // your code
       task = new MyTask();
       setList();
    }

    private void setList() {
    if (task != null)
        if (task.getStatus().equals(AsyncTask.Status.RUNNING)){
            task.cancel(true);
            task = new MyTask();
            task.execute();         
        } else if (task.getStatus().equals(AsyncTask.Status.FINISHED)) {
            task = new MyTask();
            task.execute();
        } else 
            task.execute();
    }

    class MyTask extends AsyncTask<Void, Item, Void>{
       List<Item> Itens;

       @Override
       protected void onPreExecute() {

        //your code

        list.setVisibility(View.GONE);
        adapterItem= new MyListAdapter(MyActivity.this, R.layout.item, new ArrayList<Item>());
        list.setAdapter(adapterItem);

        adapterItem.notifyDataSetChanged();
    }

    @Override
    protected Void doInBackground(Void... params) {

        Itens = getItens();
        for (Item item : Itens) {
            publishProgress(item );
        }

        return null;
    }

    @Override
    protected void onProgressUpdate(Item ... item ) {           
        adapterItem.add(item[0]);
    }

    @Override
    protected void onPostExecute(Void result) {
        //your code
        adapterItem.notifyDataSetChanged();     
        list.setVisibility(View.VISIBLE);
    }

}

}

나는 같은 문제가 있었고 그것을 해결했다. 내 문제는 listview배열 어댑터 및 필터와 함께를 사용하고 있다는 것 입니다. 이 방법 performFiltering에서는 데이터가있는 배열을 엉망으로 만들었습니다.이 방법은 UI 스레드에서 실행되지 않고 EVENTUALLY로 문제가 발생하기 때문에 문제였습니다.


이 충돌의 한 가지 원인은 ArrayList개체를 완전히 변경할 수 없기 때문입니다. 따라서 항목을 제거 할 때 다음을 수행해야합니다.

mList.clear();
mList.addAll(newDataList);

이로 인해 충돌이 해결되었습니다.


필자의 경우 기본 활동 GetFilter()TextWatcher()메소드에서 어댑터 의 메소드 호출했으며 For 루프가있는 데이터를 추가했습니다 GetFilter(). 해결책은 AfterTextChanged()기본 활동 에서 For 루프를 하위 메소드 로 변경하고에 대한 호출을 삭제했습니다.GetFilter()


또한 동일한 오류가 발생하고 AsyncTask를 사용하고 있습니다.

`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. [in ListView(2131296334, class android.widget.ListView) with Adapter... etc

adapter.notifyDataSetChanged();UI 스레드의 맨 아래 에 배치 하여 AsyncTask onPostExecute 메소드를 사용하여 문제를 해결했습니다 . 이처럼 :

 protected void onPostExecute(Void aVoid) {

 all my other stuff etc...
    all my other stuff etc...

           adapter.notifyDataSetChanged();

                }

            });
        }

이제 내 앱이 작동합니다.

편집 : 사실, 내 앱은 여전히 ​​약 10 번마다 충돌하여 동일한 오류가 발생합니다.

결국 나는 runOnUiThread이전 게시물을 보았는데 유용하다고 생각했습니다. 그래서 다음과 같이 doInBackground 메소드에 넣었습니다.

@Override
protected Void doInBackground(Void... voids) {

    runOnUiThread(new Runnable() {
                      public void run() { etc... etc...

그리고 그 adapter.notifyDataSetChanged();방법을 제거했습니다 . 이제 내 앱이 충돌하지 않습니다.


다음 해결책 중 하나를 시도하십시오.

  1. 경우에 따라 스레드 (또는 doInBackground메서드)의 데이터 목록에 새 개체를 추가하면 이 오류가 발생합니다. 해결책은 다음과 같습니다. 임시 목록을 작성하고 thread (또는 doInBackground) 에서이 목록에 데이터를 추가 한 다음 임시 목록에서 UI 스레드의 어댑터 목록으로 모든 데이터를 복사하십시오 (또는 onPostExcute).

  2. 모든 UI 업데이트가 UI 스레드에서 호출되는지 확인하십시오.


게으른 이미지 로더에 새 데이터를 추가 할 때 동일한 문제가 발생했습니다.

         adapter.notifyDataSetChanged();

       protected void onPostExecute(Void args) {
        adapter.notifyDataSetChanged();
        // Close the progressdialog
        mProgressDialog.dismiss();
         }

그것이 당신을 도울 희망


@Mullins가 말했듯이 "
아이템을 추가 notifyDataSetChanged()하고 UI 스레드에서 호출 했는데 이것을 해결했습니다. – Mullins".

내 경우에는 내가 가지고 asynctask내가 전화 notifyDataSetChanged()doInBackground()방법에서 내가 전화했을 때 문제가 해결되고 onPostExecute()난 예외를 받았다.


나는 관습을 가지고 있었고 방법의 끝이 아닌 처음 ListAdapter에 전화 super.notifyDataSetChanged()했다.

@Override
public void notifyDataSetChanged() {
    recalculate();
    super.notifyDataSetChanged();
}

나는 같은 sittuation을 가지고 있었고, listview에 내 항목이 많은 단추 그룹을 가지고 있었고 holder.rbVar.setOnclik와 같은 내 항목 내부의 부울 값을 변경하고있었습니다 ...

getView () 내부에서 메소드를 호출했기 때문에 문제가 발생했습니다. sharepreference 내부에 객체를 저장하고 있었으므로 위의 동일한 오류가 발생했습니다.

내가 어떻게 해결했는지; getView () 내에서 notifyDataSetInvalidated () 메서드를 제거했는데 문제가 사라졌습니다.

   @Override
    public void notifyDataSetChanged() {
        saveCurrentTalebeOnShare(currentTalebe);
        super.notifyDataSetChanged();
    }

나는 같은 문제가 있었다. 마침내 나는 해결책을 얻었다

목록보기를 업데이트하기 전에 소프트 키패드가 있으면 먼저 닫으십시오. 그 후에 데이터 소스를 설정하고 notifydatasetchanged ()를 호출하십시오.

내부적으로 키패드를 닫으면 listview가 UI를 업데이트합니다. 키패드를 닫을 때까지 계속 호출합니다. 데이터 소스가 변경되면이 예외가 발생합니다. onActivityResult에서 데이터가 업데이트되는 경우 동일한 오류가 발생할 수 있습니다.

 InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(v.getWindowToken(), 0);

        view.postDelayed(new Runnable() {
            @Override
            public void run() {
                refreshList();
            }
        },100L);

내 해결책 :

1)을 만듭니다 temp ArrayList.

2) doInBackground메소드 에서 무거운 작업 (sqlite row fetch, ...) 을 수행하고 임시 배열 목록에 항목을 추가하십시오.

3) onPostExecute방법으로 temp araylist의 모든 항목을 listview의 arraylist에 추가하십시오 .

note:listview에서 일부 항목을 삭제하고 sqlite 데이터베이스에서 삭제하고 sdcard에서 항목과 관련된 일부 파일을 삭제할 수도 있습니다. 데이터베이스에서 항목을 제거하고 관련 파일을 제거하고 임시 배열 목록에 추가하십시오 background thread. 그런 다음 UI thread임시 배열 목록에있는 항목을 목록보기의 배열 목록 에서 삭제하십시오.

도움이 되었기를 바랍니다.


adapter.notifyDataSetChanged()

참고 URL : https://stackoverflow.com/questions/3132021/android-listview-illegalstateexception-the-content-of-the-adapter-has-changed

반응형