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

时间:2012-07-24 12:32:24

标签: 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;

    @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) 
            {              
              ...

然后进行远程Asynch调用以从我的数据库中获取列表,并尝试在onPostExecute方法中执行此操作:

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

                    try
                    {
                        JSONArray obj = new JSONArray(result);

                        if ( obj != null )
                        {

                            for ( int i = 0; i < obj.length(); i++ )
                            {
                                JSONObject o = obj.getJSONObject(i);

                                map.put("train", "Business Name");
                                map.put("from", ">");
                                map.put("to", ">");
                                mylist.add(map);
                                map = new HashMap<String, String>();
                                map.put("train", "103(x)");
                                map.put("from", "6:35 AM");
                                map.put("to", "7:45 AM");
                                mylist.add(map);                                                                    
                            }
                        }
                    }
                    catch ( Exception e )
                    {
                    }                   

                    list.setAdapter(mSchedule);         

但是我在这一行得到了Null Pointer异常:

ListView list = new ListView (this);

但我认为通常我在postExecute方法中需要完成这项工作。任何有关如何正确执行此操作的帮助都非常感谢。

2 个答案:

答案 0 :(得分:1)

我记得并且作为一个合乎逻辑的结论:在您致电的那一刻,的引用为 null 将在 ListView 的构造函数中访问,因此将引发 NullPointerException 。如果您想动态创建它,则必须在活动 onCreate 方法中调用 ListView 构造函数。

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

答案 1 :(得分:1)

OnCreate 中,您可以定义一个新的SimpleAdapter并将其附加到ListView。这是对的。数据源(在您的情况下为mylist)此时为空,因此您将在AsyncTask填充它。

onPostExecute 中,您正在创建新的ArrayList。根据您收到的结果,您可以填写它。执行此操作后,您将再次设置适配器。由于适配器没有数据,因此无法执行任何操作。您要执行的操作是将新填充的列表提供给适配器,以便它可以使用您的数据填充ListView

解决方案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
}

<强>更新

结帐this tutorial。我使用相同的布局和相同的源来填充我的列表,但我已经改变它,所以它类似于你的情况。祝你好运:)

MainActivity

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