Android,ListView IllegalStateException:“适配器的内容已更改,但ListView没有收到通知”


188

我想做的是:运行后台线程,该线程计算ListView的内容并部分更新ListView,同时计算结果。

我必须避免的是:我无法弄乱后台线程中的ListAdapter内容,因此我继承了AsyncTask并从onProgressUpdate发布结果(向适配器添加条目)。我的适配器使用结果对象的ArrayList,对这些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次插入一次,以避免闪烁和突然的列表更改。无法以这种方式完成,请在基本列表更改时始终通知适配器。这个错误现在对我早已消失。


3
您是否致电notifyDataSetChanged()?
Denis Palnitsky

1
当然,在onProgressUpdate中会执行以下顺序:list.setVisibility(GONE)-list上的addObjectToList /同步操作/-notifyDataSetChanged()-list.setVisibility(VISIBLE)(并且不进行可见性修改,异常发生的频率更高)
捣碎

1
您是否正在其他线程上修改基础ArrayList?所有更改,甚至对适配器引用的ArrayList都必须在UI线程上进行。
Rich Schuler 2010年

2
@Qberticus-正如我明确指出的那样,我不会从其他线程修改ArrayList,而是从AcyncTask的onProgressUpdate方法修改-它在GUI线程中工作。
10:29捣毁

1
@tomash我遇到了同样的异常,我使用拉刷新来刷新,并且在执行后,我已经编写了adapter.notifyDataSetChanged();。lvAutherlist.completeRefreshing(); 但有时得到这个错误怎么解决呢

Answers:


119

我遇到过同样的问题。

我正在将项目添加到ArrayListUI线程之外。

解决方案:我已经完成了这两项工作,adding the itemsnotifyDataSetChanged()在UI线程中进行了调用。


4
我既添加了项目,又在UI线程中调用了notifyDataSetChanged(),并解决了这个问题。
Mullins

23
温和的评论,真的。
dentex

2
这是一个多线程问题,可以使用正确同步的块。没有在UI Thread上放置多余的东西并导致应用程序的响应能力下降。请在下面查看我的答案。
Javanator'1

2
对于将来的读者-在后台线程中进行计算是一件好事,但是您应该将结果传递给UI线程,并在同一代码块中将项添加到适配器基本集合并通知适配器。
粉碎2014年

4
@Mullins能否请您为您的解决方案提供示例?我也遇到了同样的问题
Jas 2015年

27

我遇到了同样的问题,但是我使用方法修复了它

requestLayout();

从班上 ListView


35
什么时候应该调用此方法?
JehandadK

3
将项目添加到ListView或更改其适配器之后的@DeBuGGeR。
Ahmet NoyanKızıltan13年

如果我要在asynctask中添加元素怎么办
Dr. aNdRO 2014年

2
仅作记录,@ Dr.aNdRO,您将结果收集在AsyncTask中。doInBackground()并保存结果以更新AsyncTask.onPostExecute()中的列表,该列表将在UI线程中运行。如果您需要随时更新,请使用也在UI线程中运行的AsyncTask.publishProgress()和AsyncTask.onProgressUpdate()。
妮可·博雷利

21

这是一个多线程问题,可以使用正确同步的块。没有在UI Thread上放置多余的东西,而导致应用程序的响应能力下降。

我也面临同样的问题。正如最被接受的答案所建议的那样,通过UI Thread更改适配器数据可以解决此问题。那会起作用,但这是一种快速简便的解决方案,但不是最佳解决方案。

如您所见,这是正常情况。从后台线程更新数据适配器并在UI线程中调用notifyDataSetChanged。

当ui线程正在更新视图并且另一个后台线程再次更改数据时,将出现非法状态异常。那一刻引起了这个问题。

因此,如果您将同步所有更改适配器数据并进行notifydatasetchange调用的代码。这个问题应该消失了。对于我来说,我仍然从后台线程更新数据。

这是我的案例特定代码,供其他人参考。

我在主屏幕上的加载器在后台将电话簿联系人加载到我的数据源中。

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

此PhoneBookManager.getPhoneBookContacts从电话簿中读取联系人并将其填充在哈希图中。直接用于列表适配器绘制列表。

屏幕上有一个按钮。这将打开一个列出这些电话号码的活动。如果我在上一个线程完成其工作之前直接将setAdapter设置在列表上,则快速导航的情况较少发生。它弹出一个异常。这是此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());    
        }
    }

}

希望这可以帮助


对不起,你是怎么做到的?您如何同步后台线程代码和notifydatasetchange调用?我在过滤AutocompleteTextView上的数据时使用了doInBackground,并且遇到了相同的问题...您能建议我一些解决方法吗?
tonix 2014年

@ user3019105-同步两个后台线程。一种在后台更新数据,另一种使用可用的handler.post方法或runOnUiThread方法通知ui线程setAdadpter或notifydatasetchanged。对于我的特殊情况,我将两个加载器同步,并将它们的doInBackground同步在单个对象上。首先开始在初始屏幕本身上准备数据,以便快速将其用于仪表板屏幕。那是我的需要。
Javanator 2014年

您能否发布此实现的代码段?就我而言,我已解决了在适配器上调用clear()的问题,创建了一个已过滤对象的临时ArrayList <T>,然后调用了addAll(tmpArrayList),最后调用了notifyDataSetChanged()。我在主线程上运行的publishResult()Filter方法内进行所有这些调用。您认为这是一个可靠的解决方案吗?
tonix

@ user3019105检查编辑的答案。希望它对您现在有所帮助
Javanator

这个答案需要大量阅读,以了解其工作原理,tutorials.jenkov.com
java

15

我通过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();
        }
    });
}

7

我编写了这段代码,并使其在2.1模拟器映像中运行了大约12个小时,并且没有收到IllegalStateException。我要给android框架带来对此疑问的好处,并说这很可能是您代码中的错误。我希望这有帮助。也许您可以使其适应列表和数据。

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);
    }
}

感谢您的工作!我注意到,对于ArrayAdapter方法,hasStableIds()= false; 由于行在每个notifyDataSetChanged()之前进行了排序,因此我的实现返回true,但不太正确。我将尝试-如果崩溃仍然存在,我将继续调查。最好的祝福!
20:15捣毁

4

几天前,我遇到了同样的问题,每天导致数千次崩溃,大约0.1%的用户遇到了这种情况。我尝试了setVisibility(GONE/VISIBLE)requestLayout(),但是崩溃计数仅减少了一点。

我终于解决了。没事setVisibility(GONE/VISIBLE)。没事requestLayout()

最终,我发现原因是我在更新数据后使用了a Handler进行调用notifyDataSetChanged(),这可能导致以下情况:

  1. 将数据更新到模型对象(我称其为数据源)
  2. 用户触摸listview(可能会调用checkForTap()/ onTouchEvent()并最终调用layoutChildren()
  3. 适配器从模型对象获取数据并调用notifyDataSetChanged()和更新视图

而我又错在getCount()getItem()而且getView(),我直接用字段的数据源,而不是将它们拷贝到适配器。所以最终在以下情况下崩溃:

  1. 适配器更新最后响应给出的数据
  2. 当下一个响应返回时,数据源将更新数据,这会导致项目数更改
  3. 用户触摸列表视图,可以是轻按,移动或翻转
  4. getCount()并被getView()调用,并且listview发现数据不一致,并引发类似的异常java.lang.IllegalStateException: The content of the adapter has changed but...IndexOutOfBoundException如果您在中使用页眉/页脚,则是另一个常见的例外ListView

因此解决方案很容易,当处理程序触发适配器获取数据并调用时,我只需将数据从DataSource复制到适配器notifyDataSetChanged()。崩溃现在再也不会发生。


1
这是我的问题。在我的情况下,getCount()返回在调用notifyDataSetChanged之前可用的新计数。由于列表是“虚拟的”,因此我现在在我的notifyDataSetChanged方法中捕获了更新的计数,然后在通过getCount()要求计数时返回此缓存的计数。
格伦

3

如果这种情况是间歇性发生的,事实证明,只有在单击“加载更多”最后一项后滚动列表时,才出现此问题。如果未滚动列表,则一切正常。

经过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。


我有一个类似的问题。您能否建议如何解决它。
May13ank 2015年

如果查看上面的2个代码示例,您将在ListView中看到mAdapter,在ListView(AdapterView)的父级中看到getAdapter()。如果重写getAdapter(),则getAdapter()的结果可能不是mAdapter。如果2个适配器的计数不同,则会出现错误。
aaronvargas

3

我的问题与将Filter和ListView一起使用有关。

在设置或更新ListView的基础数据模型时,我正在执行以下操作:

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

filter()最后一行的调用将(并且必须)导致notifyDataSetChanged()在Filter的publishResults()方法中被调用。有时候这可能还可以,特别是在我的快速Nexus 5中。但是实际上,它隐藏了一个错误,您可能会在速度较慢的设备或资源密集型情况下注意到这一错误。

问题在于,过滤是异步完成的,因此在UI线程中,在filter()语句的结尾和对的调用之间publishResults(),某些其他UI线程代码可能会执行并更改适配器的内容。

实际的修复很容易,只需notifyDataSetChanged()在请求执行过滤之前也调用即可:

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

3

如果Feed对象,我有一个列表。它是从无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;
    }
}

2

我正面临着完全相同的错误日志的相同问题。就我而言onProgress(),AsyncTask使用将值添加到适配器mAdapter.add(newEntry)。为了避免UI响应速度降低,我设置mAdapter.setNotifyOnChange(false)mAdapter.notifyDataSetChanged()第二次调用4次。每秒对数组进行排序。

效果很好,看起来很容易上瘾,但是不幸的是,可以经常触摸显示的列表项来使其崩溃。

但是看来我已经找到了可以接受的解决方法。 我的猜测是,即使您仅在ui线程上工作,适配器也不会在不调用的情况下接受对其数据的许多更改notifyDataSetChanged(),因此,我创建了一个队列,该队列将存储所有新项,直到上述300ms结束。如果到了这一刻,我将所有存储的项目一次性添加并致电notifyDataSetChanged()。到现在为止,我再也无法使列表崩溃了



2

即使我在XMPP通知应用程序中遇到了同样的问题,也需要将接收者消息添加回列表视图(使用实现ArrayList)。当我尝试通过MessageListener(单独的线程)添加接收者内容时,应用程序退出并出现上述错误。我通过将内容添加到Activity类中属于我的arraylistsetListviewadapaterthrough runOnUiThread方法来解决此问题。这解决了我的问题。


1

我遇到了类似的问题,这是我如何解决的情况。我验证是否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);
    }

}

}

1

我有同样的问题,我解决了。我的问题是我在使用listview带阵列适配器和过滤器的。在该方法上,performFiltering我搞砸了具有数据的数组,这是问题所在,因为此方法未在UI线程上运行,并且实际上它引起了一些问题。


1

导致崩溃的原因之一是ArrayList对象无法完全更改。因此,当我删除一个项目时,我必须这样做:

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

这为我修复了崩溃。


1

在我的情况下,我GetFilter()TextWatcher()主Activity 上的方法调用了适配器上的方法,并在上添加了For循环GetFilter()。解决方法是将AfterTextChanged()主活动上的For循环更改为sub方法,并删除对GetFilter()


1
请阐明您的解决方案。我的处境也像你/
nAkhmedov 2014年


0

我也得到完全相同的错误,并使用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次中有1次崩溃,并给出了相同的错误。

最终,我遇到了runOnUiThread上一篇文章,我认为这可能很有用。所以我把它放在我的doInBackground方法中,就像这样:

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

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

我删除了该 adapter.notifyDataSetChanged();方法。现在,我的应用程序永不崩溃。


0

请尝试以下解决方案之一:

  1. 有时,如果将新对象添加到线程(或doInBackground方法)的数据列表中,则会发生此错误。解决方案是:创建一个临时列表doInBackground,然后在线程(或)中向该列表添加数据,然后将所有数据从该临时列表复制到UI线程(或onPostExcute)中的适配器列表。

  2. 确保在UI线程中调用了所有UI更新。


0

我在懒惰的图像加载器中添加新数据时遇到了同样的问题

         adapter.notifyDataSetChanged();

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

希望对你有帮助


0

就像@Mullins所说:“
我既添加了项目,又notifyDataSetChanged()在UI线程中调用了,我解决了。– Mullins”。

在我的情况下,当我从中调用时,我收到了异常,asynctask并调用notifyDataSetChanged()了该doInBackground()方法,问题得以解决onPostExecute()


0

我有一个自定义ListAdapter,并super.notifyDataSetChanged()在方法的开始而不是结束时调用

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

0

我有相同的状态,我在列表视图上有很多按钮组,并且正在更改项目内部的一些布尔值,例如holder.rbVar.setOnclik ...

发生我的问题是因为我在getView()中调用了一个方法;并在sharepreference中保存一个对象,所以上面我有同样的错误

我是怎么解决的?我在getView()中删除了我的方法以notifyDataSetInvalidated()并解决了问题

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

0

我有同样的问题。终于我得到了解决方案

在更新列表视图之前,如果存在软键盘,请先将其关闭。之后,设置数据源并调用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);

0

我的解决方案:

1)创建一个temp ArrayList

2)做你繁重的工作(sqlite row fetch,...) doInBackground,并将项目添加到temp arraylist中。

3)将临时列表列表中的所有项目添加到方法中的列表视图的数组列表中onPostExecute

note:您可能想要从listview中删除一些项目,还希望从sqlite数据库中删除,还可能从sdcard中删除一些与项目相关的文件,只需从数据库中删除项目并删除其相关文件,然后将它们添加到temp arraylist中background thread。然后UI thread从列表视图的arraylist 中删除temp arraylist中存在的项目。

希望这可以帮助。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.