Android如何正确通知ListView更改的数据集

Android如何正确通知ListView更改的数据集,android,listview,Android,Listview,我正在尝试更新我的列表并在活动中显示更新的列表。每次这样做,我都会得到以下错误 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. 这是我的代码,我使用Asy

我正在尝试更新我的列表并在活动中显示更新的列表。每次这样做,我都会得到以下错误

 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.
这是我的代码,我使用AsyncTask来实现这个任务。我在适配器上调用notifyDataSetChanged(),但它似乎不起作用。我做错了什么

  class MyTask extends AsyncTask<Context, Integer, String> {

    @Override
    protected String doInBackground(Context... params) {
        GregorianCalendar currentDateclone = (GregorianCalendar) currentDate.clone();
        ListPopulater2.listPopulate(currentDateclone, 7, items, Id);
                    //method to update list info




    }

    // -- gets called just before thread begins
    @Override
    protected void onPreExecute() {
        progressdialog = ProgressDialog.show(SectionListExampleActivity.this, "", "Loading..."); //display progress bar
        super.onPreExecute();

    }

    // -- called as soon as doInBackground method completes
    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        Log.d("postExecute", "here");
                    adapter.notifyDataSetChanged();

        progressdialog.cancel();
    }
}
类MyTask扩展了AsyncTask{
@凌驾
受保护字符串doInBackground(上下文…参数){
GregorianCalendar currentDateclone=(GregorianCalendar)currentDate.clone();
ListPopulater2.ListPopulater(currentDateclone,7,items,Id);
//更新列表信息的方法
}
//--在线程开始之前被调用
@凌驾
受保护的void onPreExecute(){
progressdialog=progressdialog.show(SectionListExampleActivity.this,“,”Loading…);//显示进度条
super.onPreExecute();
}
//--在doInBackground方法完成后立即调用
@凌驾
受保护的void onPostExecute(字符串结果){
super.onPostExecute(结果);
Log.d(“执行后”、“此处”);
adapter.notifyDataSetChanged();
progressdialog.cancel();
}
}
尝试移动:

ListPopulater2.listPopulate(currentDateclone, 7, items, Id);
到您的
onPostExecute

这样做之所以有效,是因为您需要在完成所有后台活动后更新列表,而不是在您执行此操作时。您可以使用
onProgressUpdate
,但这是用于进度对话框的。更新列表视图应该在您拥有所有数据之后进行,否则,您将得到您所做的错误,因为UI在主线程上运行,并且您正试图使用后台线程更新它

至于进度对话框,有一个目的。如果您正在做一些需要一段时间才能完成的事情,该对话框将告诉用户您离完成后台任务有多近


希望这是有道理的

当你想做一些处理UI的事情时,你必须在UI线程中完成这项任务。 因此,您可以使用两种方法:

  • 使用runOnUi()方法
  • 使用OnPostExecute()方法

  • 您必须在listView中设置适配器的位置使用notifyDatasetchanged()。

    这是有效的,但有什么解释吗?同样,这也扼杀了ProgressDialogy的用途我有点理解您的意思,但是如果我将populate方法移动到onPostExecute,那么doInBackground方法中没有任何操作。我对AsyncTask的理解是,加载可以在后台完成,然后在完成后调用onPostExecute。我认为在方法listPopulate中,您试图更新一些在onPostExecute中未得到反映的数据模型,可能是因为doInBackground在后台线程中运行?对。在
    doInBackground
    中,您在一个单独的线程上运行。这适用于从web服务中提取数据、解析数据等。当您想要更新列表时,必须在主线程上进行更新,因为列表是为用户准备的,主线程是UI线程。除非在主线程上进行更新,否则无法更新适配器。在您的方法中,您正在后台线程上克隆数据,然后在克隆完成后进行更新。它从网络上提取数据,只是更新信息,实际上并不更新列表。是因为我正在更新适配器所依赖的信息吗?与您的问题无关,但您为什么在
    onPostExecute(…)
    中使用
    runOnUiThread(…)
    AsyncTask
    (除了
    doInBackground(…)
    )的所有方法都在UI线程上运行。我刚刚尝试过的一些方法,没有它也可以运行。我只是为了清楚起见把它去掉了