Android-在异步调用后更新ListAdapter时遇到问题

Android-在异步调用后更新ListAdapter时遇到问题,android,android-layout,android-asynctask,Android,Android Layout,Android Asynctask,我正在设置一个ListView适配器,如下所示: public class SeeAllQuestionsActivity extends Activity { //ArrayAdapter<Question> adapter; SimpleAdapter mSchedule = null; ListView list = new ListView (this); TextView loading_questions = null;

我正在设置一个ListView适配器,如下所示:

public class SeeAllQuestionsActivity extends Activity
{
    //ArrayAdapter<Question> adapter;   
    SimpleAdapter mSchedule = null;
    ListView list = new ListView (this);

    TextView loading_questions = null;

    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);        
        setContentView(R.layout.all_question_page);

        TextView loading_questions = (TextView) findViewById(R.id.loading_questions);

        list = (ListView) findViewById(R.id.list);

        ArrayList<HashMap<String, String>> mylist = new ArrayList<HashMap<String, String>>();
        HashMap<String, String> map = new HashMap<String, String>();

        mSchedule = new SimpleAdapter(this, mylist, R.layout.questions_list,
                new String[] {"train", "from", "to"}, 
                new int[] {R.id.TRAIN_CELL, R.id.FROM_CELL, R.id.TO_CELL});

        list.setAdapter(mSchedule);

        list.setTextFilterEnabled(true);

        list.setOnItemClickListener(new OnItemClickListener() 
        {
            public void onItemClick(AdapterView<?> parent, View view,
                int position, long id) 
            {              
              ...

但我认为,在postExecute方法中,通常情况下,我对如何实现这一点还很不了解。非常感谢您对如何正确执行此操作的任何帮助。

我记得,这是一个合乎逻辑的结论:在您通话的那一刻,的参考值为将在列表视图的构造函数中访问,因此将引发NullPointerException。如果要动态创建它,必须在活动的onCreate方法中调用ListView构造函数


如果可能的话,至少最好按照MartijnVanMierloo的建议来实现它。

在创建时定义一个新的SimpleAdapter并将其附加到ListView。这是正确的。此时数据源(
mylist
)为空,因此您将在
AsyncTask
中填充它

onPostExecute中,您正在创建一个新的
ArrayList
。根据您收到的结果,您可以填写它。完成此操作后,将再次设置适配器。因为适配器没有数据,所以不会执行任何操作。。您要做的是,将新的填充列表提供给适配器,以便它可以用您的数据填充
列表视图

解决方案1

onPostExecute {
   // create a list to store your data
   new ArrayList

   // fill the new list with the data you received (result)
   fillArrayList from JSON

   // create an adapter and give the new list with it
   mAdapter = new SimpleAdapter(.., ArrayList, ...)
   listView.setAdapter(mAdapter);   
}
这是一种方法,适合您当前的实现

解决方案2

我会选择这个解决方案

onPostExecute {
    // don't create a new arraylist but use the mylist-object you created in the OnCreate
    fill mylist object with new data 

    // mylist is the datasource of your adapter and it is now changed.
    // let the ListView know his adapter received new information
    mSchedule.notifyDataSetChanged
}
更新

退房。我使用相同的布局和相同的来源来填充我的列表,但我已经更改了它,所以它与您的情况类似。祝你好运:)

主要活动

公共类MainActivity扩展活动{
私人列表地图;
专用SimpleAdapter适配器;
创建时的公共void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView lv=(ListView)findViewById(R.id.ListView);
字符串[]from=新字符串[]{“rowid”、“col_1”、“col_2”、“col_3”};
int[]to=newint[]{R.id.item1,R.id.item2,R.id.item3,R.id.item4};
//我的数据
fillMaps=newarraylist();
//创建一个适配器,它将告诉我的ListView要显示的内容。。
//fillMaps仍然是空的,因此此时将显示我的ListView
//没什么。
adapter=new simpledapter(this,fillMaps,R.layout.row,from,to);
低压设置适配器(适配器);
//从某处检索数据
新建UpdateListWithAsyncTask().execute();
}
私有类UpdateListWithAsyncTask扩展了AsyncTask{
受保护的Void doInBackground(Void…参数){
//做事
返回null;
}
受保护的void onPostExecute(void结果){
//填充适配器拥有的数据源
对于(int i=0;i<10;i++){
HashMap=newHashMap();
map.put(“rowid”和“+i”);
地图放置(“第1栏”、“第1栏”项目+i);
地图放置(“col_2”、“col_2_项目”+i);
地图放置(“第三栏”、“第三栏”项目+i);
fillMaps.add(map);
}
//我的数据源现在已更改,我希望我的适配器知道这一点,并且
//更新我的列表视图
adapter.notifyDataSetChanged();
}
}
}

Your line
ListView list=newlistview(这个)不是必需的。您在XML中定义了ListView,并且可以像以前一样将其分配给变量:
list=(ListView)findViewById(R.id.list)@MartijnVanMierloo哦,对了,说得好。我现在要试试这个,但我认为服务器返回后我的代码仍然有点混乱……不管怎样……现在就用你的建议试试。@MartijnVanMierloo你的建议确实阻止了崩溃,但是仍然存在一个问题,屏幕上没有显示我设置的列表。你确定
结果
不为空吗?@MartijnVanMierloo是100%确信结果不为空,因为我一直使用此后端代码,另外,当我以不同的方式使用listview时,这段代码也可以使用。我只是用“this”注释掉了这一行,并将这一行放在onCreate:list=(listview)findViewById(R.id.list)。。。但是当程序从异步调用返回时,我仍然无法让列表项显示在屏幕上。知道为什么吗?是的,你建议的第二个解决方案看起来很好。我对它的工作原理有点困惑,因为mSchedule只是一个映射,而不是列表。我现在正在尝试…我注释掉了list.setAdapter(mSchedule);并添加了mSchedule.notifyDataSetChanged();在我设置数据之后。现在试一试..在您的问题中显示的代码中,
mSchedule
是您的
ListView
的适配器吗?
是的,mSchedule被定义为simpledapter,如mSchedule=new simpledapter(this,mylist,R.layou.questions_list,new String[]{“train”,“from”,“to”},new int[]{R.id.TRAIN_CELL,R.id.FROM_CELL,R.id.TO_CELL});我刚刚运行了代码,列表没有填充。(…我想我们没有通知MSCreachedule映射不同。我不知道如何做。您还在
OnPostExecute
中创建新的ArrayList吗?
onPostExecute {
   // create a list to store your data
   new ArrayList

   // fill the new list with the data you received (result)
   fillArrayList from JSON

   // create an adapter and give the new list with it
   mAdapter = new SimpleAdapter(.., ArrayList, ...)
   listView.setAdapter(mAdapter);   
}
onPostExecute {
    // don't create a new arraylist but use the mylist-object you created in the OnCreate
    fill mylist object with new data 

    // mylist is the datasource of your adapter and it is now changed.
    // let the ListView know his adapter received new information
    mSchedule.notifyDataSetChanged
}
public class MainActivity extends Activity {

    private List<HashMap<String, String>> fillMaps;
    private SimpleAdapter adapter;

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ListView lv = (ListView) findViewById(R.id.listview);

        String[] from = new String[] { "rowid", "col_1", "col_2", "col_3" };
        int[] to = new int[] { R.id.item1, R.id.item2, R.id.item3, R.id.item4 };

        // My data
        fillMaps = new ArrayList<HashMap<String, String>>();

        // Create an adapter which will tell my ListView what to show..
        // fillMaps is still empty so at the moment it my ListView will show
        // nothing.
        adapter = new SimpleAdapter(this, fillMaps, R.layout.row, from, to);
        lv.setAdapter(adapter);

        // Retreive data from somewhere
        new UpdateListWithAsyncTask().execute();
    }

    private class UpdateListWithAsyncTask extends AsyncTask<Void, Void, Void> {
        protected Void doInBackground(Void... params) {
            // do stuff
            return null;
        }

        protected void onPostExecute(Void result) {
            // Fill your datasource that your adapter has. In my case fillMaps
            for (int i = 0; i < 10; i++) {
                HashMap<String, String> map = new HashMap<String, String>();
                map.put("rowid", "" + i);
                map.put("col_1", "col_1_item_" + i);
                map.put("col_2", "col_2_item_" + i);
                map.put("col_3", "col_3_item_" + i);
                fillMaps.add(map);
            }

            // my datasource is now changed, I want my adapter to know this and
            // update my ListView
            adapter.notifyDataSetChanged();
        }
    }
}