【问题标题】:Android - having trouble updating a ListAdapter after an Asynch callAndroid - 在异步调用后更新 ListAdapter 时遇到问题
【发布时间】:2012-07-24 22:34:48
【问题描述】:

我正在设置这样的 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) 
            {              
              ...

然后进行远程异步调用以从我的数据库中获取列表,并尝试在 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);         

但我在这一行得到一个空指针异常:

ListView list = new ListView (this);

但我认为总的来说,我在 postExecute 方法中需要如何完成这件事还有很长的路要走。非常感谢有关如何正确执行此操作的任何帮助。

【问题讨论】:

  • 您的线路ListView list = new ListView (this); 不是必需的。您在 XML 中定义了您的 ListView,您可以将它分配给一个变量,就像您已经做的那样:list = (ListView) findViewById(R.id.list);
  • @MartijnVanMierloo 哦,对了,好点子。我现在要试试这个,但我认为服务器返回后我的代码仍然有点混乱......不管......现在尝试你的建议。
  • @MartijnVanMierloo 您的建议确实阻止了崩溃,但仍然存在一个问题,即屏幕最终没有显示我设置的列表。
  • 您确定result 不为空吗?
  • @MartijnVanMierloo 是的 100% 确信结果不为空,因为我一直使用这个后端代码,而且当我以不同的方式拥有列表视图时,这个代码曾经可以工作。

标签: android android-layout android-asynctask


【解决方案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();
        }
    }
}

【讨论】:

  • 是的,您建议的第二种解决方案看起来非常好。我对它的工作原理有点困惑,因为 mSchedule 只是地图而不是列表。我现在正在尝试...我注释掉了 list.setAdapter(mSchedule);并添加了 mSchedule.notifyDataSetChanged();在我设置数据之后。现在试试..
  • 在您在问题中显示的代码中,mSchedule 是您的 ListView 的适配器
  • 是的,mSchedule 被定义为这样的 SimpleAdapter 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});
  • 我刚刚运行了代码,但没有填充列表。 :( ...我认为我们没有通知 mSchedule 地图不同。我不知道该怎么做。
  • 你还在你的OnPostExecute里面创建一个新的ArrayList吗?
【解决方案2】:

据我所知,作为一个合乎逻辑的结论:在你打电话的那一刻,this 的引用是 nullthis 将在您的 ListView 的构造函数中访问,因此将引发 NullPointerException。如果您想动态创建它,您必须在 ActivityonCreate 方法中调用 ListView 构造函数。

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

【讨论】:

  • 我刚刚用“this”注释掉了这一行,并在 onCreate 中有这一行: list = (ListView) findViewById(R.id.list); ...但是当程序从异步调用返回时,我仍然无法让列表项显示在屏幕上。知道为什么不?
猜你喜欢
  • 1970-01-01
  • 2017-01-10
  • 1970-01-01
  • 1970-01-01
  • 2021-08-29
  • 2020-11-05
  • 1970-01-01
  • 1970-01-01
  • 2016-06-28
相关资源
最近更新 更多