【问题标题】:Best way to wait a method that get data asynchronously from database to populate a listview等待从数据库异步获取数据以填充列表视图的方法的最佳方法
【发布时间】:2016-06-21 11:35:10
【问题描述】:

我想用从 DB 异步检索的数据填充 listView, 问题是,如果我设置适配器,它会抛出空指针,因为数据尚未到达,当我收到数据时执行一个方法,那么我可以在这个方法中调用什么来填充我的列表视图?我尝试将布局传递给此类以在收到数据但不起作用时直接填充列表视图(没有发生任何事情)

我认为使用 AsyncTask 添加 wait() 是一个好主意,当这个“检索数据方法”被触发时调用 notify() 但我不知道如何从另一个类的 asynctask 调用 notify()...

我也不确定 asynktask 是否是最好的方法,有什么想法吗? 如果有帮助,我正在使用 retrofit2

listview 创建/填充代码

private List<TmOfsDTO> prepareList() {
    List<TmOfsDTO> list;
    try {
        // Create list of items
        ListObtainer listObtainer = new ListObtainer(this);
        list = listObtainer.getTmOfsDTOList(user); // this method returns list of objects from DB
    } catch (Exception e) {
        list = null;
        e.printStackTrace();
    }
    return list;
}

private void populateListView(List<TmOfsDTO> lista) {

    // Build Adapter
    OrderAdapter orderAdapter = new OrderAdapter(this, 0, lista);
    // orderAdapter.getView()

    Log.d("LSO", ".....");
    // Configure listview
    //View rootView = View.inflate(this, R.layout.activity_ordenes, null);
    ListView listView = (ListView) findViewById(R.id.lvOrdenes);
    listView.setAdapter(orderAdapter);
    //listView.invalidateViews();
    //listView.refreshDrawableState();
    Log.d("LSO", ".......");

最后更新:
** 当我接收数据时,我正在做正确的通知,将适配器传递给类并调用: orderAdapter.notifyDataSetChanged();

但问题是我错过了添加每个项目: orderAdapter.add(orden);

在通知之前,现在似乎工作得很好**

【问题讨论】:

  • 加载器,了解加载器框架
  • " 问题在于,如果我设置了适配器,它会抛出空指针,因为数据还没有到达”——这部分听起来很可疑。如果您有一个有效的适配器,则数据是否已到达无关紧要(在将数据添加到适配器之前,它应该在列表中不显示任何内容)
  • 能否请您通过相关的logcat部分?那么匹配的代码呢?

标签: android multithreading listview asynchronous retrofit


【解决方案1】:

当您在上面显示的 logcat 时,lista 为空。您正在将此列表传递给适配器。但是如果你没有初始化变量lista会抛出空指针异常。

建议初始化您传递给适配器的列表。然后当数据进来你添加数据lista并调用方法adapter.notifyDataSetChanged()

以下似乎导致空指针异常

} catch (Exception e) {
        list = null;
        e.printStackTrace();
}

所以除了初始化之外,你也不应该分配 null。

【讨论】:

  • 在 catch 中处理糟糕的代码设计并不是一个可靠的解决方案。
  • 如果适配器是在调用getListFromDB方法后创建的,当我收到数据时如何调用adapter.notifyDataSetChanged()?
  • 将 OrderAdapter orderAdapter 设为类变量,然后在收到数据时设置 orderAdapter.setDayaSetChanged()
  • 确实,try and catch 绝对是一个很好的解决方案。但这只是为了指出当前的失败点。代码确实应该改进。但当时迈出了一步。失败,修复,改进
  • 谢谢哥们,我解决了它,将适配器传递给接收数据并将项目添加到其中的内部类,然后调用 notifyDataSetChanged()
【解决方案2】:

无论如何,您最好使用 RecyclerView。这是新支持库的一部分,比旧的 ListView 更有效。

这里的一些关键问题是数据库是否是本地的。如果您的手机上有一个 sqlite3 数据库,那么您应该编写一些类来将数据库信息加载到可以存储到数组中并非常容易传递到 RecyclerView.Adapter 的对象中。

如果您是远程加载,那么在尝试加载 RecyclerView 之前使用 AsyncTask 将数据同步到手机上会好 100%,否则会出现这些错误。

您可以将一个项目从远程数据库加载到 ArrayList 中,将其传递给 RecyclerView,然后继续从远程数据库加载,并在每个项目添加到列表时通知 RecyclerView 更改。

【讨论】:

  • 添加 sqlite 并将其与远程数据库同步听起来不错......但现在需要太多时间来实现,我需要一个更简单的解决方案,因为我需要 listview 为今天工作
【解决方案3】:

为您的适配器创建一个不同的构造函数,该构造函数不接收要在其中显示的数据。当你拥有它时,它不会崩溃。

要获取您的数据,请为您的项目创建一个本地 List 并使用以下内容填充它:

public void setData(List<MyObject> data){
this.mData = data;
notifyDataSetChanged();
}

另外,不要忘记在 getItem 等方法中处理可能出现的空指针错误。

【讨论】:

    【解决方案4】:

    假设我们在 viewDidLoad 方法中。我建议您执行以下操作:

    • 在你的适配器类中创建公共方法:setData,它调用adapter.notifyDataSetChanged()
    • 通过回调函数向后端发送请求
    • 显示加载/进度对话框
    • 通过传递空数组(非空)初始化适配器
    • 当回调被触发并且您获得列表调用适配器的 setData 并隐藏进度对话框时。

    【讨论】:

    • "通过回调函数向后端发送请求"我该怎么做
    • 通过使用委托或其他回调机制。
    【解决方案5】:

    如果您使用 Fragments,只需在数据提取后再次致电 setAdapter()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-06
      • 1970-01-01
      • 2023-03-13
      • 2010-10-05
      • 2020-01-08
      • 2019-07-29
      • 2017-08-04
      • 2012-05-02
      相关资源
      最近更新 更多