【问题标题】:ListView adapter getView() not called if populated after onCreate()如果在 onCreate() 之后填充,则不会调用 ListView 适配器 getView()
【发布时间】:2012-04-19 01:21:34
【问题描述】:

我遇到了一个相当令人费解的问题。如果我尝试使用 AsyncTask 填充 ListView,则永远不会调用该 ListView 适配器上的 getView()。请注意,这是 Activity 启动时此 ListView 的初始数据填充。由于 ListView 是从 HTTP 填充的,因此需要 AsyncTask。

我有以下简单的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    >
<ListView  
    android:id="@+id/transactionListView"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"
    android:divider="#CCCCCC"
    android:dividerHeight="1px"
    />
</LinearLayout>

还有一个基本的 onCreate():

public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    mainListView = (ListView)findViewById(R.id.transactionListView);
    this.populateListView();
}

你可以看到哪些调用:

private void populateListView()
{
    populateListViewTask task = new populateListViewTask();
    task.execute();
}

最后,AsyncTask onPostExecute():

protected void onPostExecute(Void result)
{
    lvAdapter = new CustomArrayAdapter(MainActivity.this, R.layout.listitem, data);
    mainListView.setAdapter(lvAdapter);
}

当然,实际的实现要复杂一些,但我已经消除了任何其他错误来源,除了在上述配置中没有调用 getView()。如果在 onPostExecute() 中添加 lvAdapter.getCount(),我得到 30(这是我所期望的,因为真实代码的 HTTP/XML 解析部分工作正常)。我也尝试添加 notifyDataSetChanged(),只是为了笑,但 CustomArrayAdapter,顾名思义,扩展了 ArrayAdapter。我也在视图上尝试了 invalidate() ,也没有效果。

但是,如果在调用 AsyncTask 之前将 onCreate() 更改为像这样具有单个虚拟列表项:

public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    mainListView = (ListView)findViewById(R.id.transactionListView);

    //Add dummy list item
    TestDataStructure[] data = new TestDataStructure[1];|
    data[0] = new TestDataStructure();
    data[0].item = "Dummy List Item";
    lvAdapter = new CustomArrayAdapter(MainActivity.this, R.layout.listitem, data);
    mainListView.setAdapter(lvAdapter);

    this.populateListView();
}

getView() 将在 onPostExecute() 调用之后被正确调用,ListView 将使用来自 AsyncTask 的新项目正确填充。我的预感是,在原来的情况下,Android 在 Activity 创建周期中确定了布局中项目的结构和可见性,并决定 transactionListView 因为它是空的而不可见,从而阻止它在新适配器时调用 getView()设置好了。

关于如何在不添加虚拟列表项的情况下解决此问题的任何想法(在 AsyncTask 完成之前当然可见)?我的活动扩展了 Activity,而不是 ListActivity。

谢谢!

【问题讨论】:

    标签: android listview android-asynctask


    【解决方案1】:

    如果您的数据是ArrayList&lt;String&gt;,您可以在onCreate() 中分配此data = new ArrayList&lt;String&gt;(); 并为此分配适配器,这将使您的ListView 保持为空,直到您完成异步任务,您可以使用您的值分配数据,并且用这个adapter.notifyDataSetChanged() 通知适配器数据已更改。

    【讨论】:

    • 不幸的是,数据是一个对象数组,一旦我加载了虚拟项目,getView() 就会尝试对其进行操作。因此,我不能将任何空值传递到要发送到适配器的数据中。
    • @Nishmaster:在等待 AsyncTask 完成时将适配器的数据设置为 new ArrayList&lt;MyCustomObject&gt;() 就可以了。至于您的具体问题,我将您的示例代码放入一个虚拟项目中,它似乎运行没有问题。我也在做一些与你在我自己的项目中描述的几乎相同的事情(具有自定义对象类型的 ArrayAdapter 和所有)并且没有看到这个问题,我也没有遇到你报告的 notifyDataSetChanged() 问题.这不是一个有趣的答案,但也许错误源于代码中的其他地方?
    【解决方案2】:

    听起来和看起来您需要在填充适配器后在适配器上调用 notifyDataSetChanged()。这必须从UI线程调用,所以把它放到直接从postExecute()方法调用的代码中。

    如果有帮助,请将其标记为答案。

    【讨论】:

    • 如果您在我上面的原始问题中注意到,我已经尝试过但没有成功。我不认为 notifyDataSetChanged() 对 ArrayAdapters 有任何影响。
    猜你喜欢
    • 2018-02-10
    • 1970-01-01
    • 2015-11-22
    • 2019-09-09
    • 1970-01-01
    • 2016-11-12
    • 1970-01-01
    • 2011-11-15
    • 1970-01-01
    相关资源
    最近更新 更多