【问题标题】:BaseAdapter notifyDatasetChanged() called but getView() is never calledBaseAdapter notifyDatasetChanged() 被调用,但 getView() 从未被调用
【发布时间】:2016-06-18 17:17:01
【问题描述】:

我有一个自定义适配器,可以可视化订单列表中的每一行。

public class OrderRowAdapter extends BaseAdapter implements OnClickListener {
    OrderList items_;
    LayoutInflater inflater_;
    int list_view_resource_id_;
    private final String TAG = "OrderRowAdapter";

    public OrderRowAdapter(Context context, int list_view_resource_id,
            OrderList items) {
        this.list_view_resource_id_ = list_view_resource_id;
        this.items_ = items;
        this.inflater_ = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    public Object getItem(int position) {
        return items_.getOrders(position);
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        Log.d(TAG, "View updated for item in position = " + position);

        View v = convertView;
        if (v == null) {
            v = inflater_.inflate(list_view_resource_id_, parent);
        }

        Order item = items_.getOrders(position);
        if (item != null) {
            TextView order_info_tv = (TextView) v.findViewById(R.id.order_info);
            TextView order_status_tv = (TextView) v.findViewById(R.id.order_status);

            if (order_info_tv != null) {
                order_info_tv.setText(
                        String.format("For customer: %s\nTotal of %d items", item.getCustomerId(), item.getItemsCount()));
            }
            if (order_status_tv != null) {
                order_status_tv.setText("Status: " + getStatusText(item.getStatus()));
            }
        }
        return v;
    }

    public int getCount() {
        if (items_ == null) {
            Log.d(TAG, "Null so get count returned 0");
            return 0;
        } else {
            Log.d(TAG, "Get count returned " + items_.getOrdersCount());
            return items_.getOrdersCount();
        }
    };

从网络服务查询新的订单列表后,我想更新 ListView 的内容,所以我让我的 Activity 在调用 notifyDataSetChanged() 之前进行更新

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

    initThreading();
    findViews();
    setUrls();

    // Load the list of order from disk
    try {
        order_list_ = OrderList.parseFrom(new FileInputStream(
                "/sdcard/orderList.bin"));
    } catch (FileNotFoundException e) {
        Log.e(TAG, "Cannot find the file", e);
    } catch (IOException e) {
        Log.e(TAG, "Cannot read the file", e);
    }

    order_row_adapter_ = new OrderRowAdapter(OrderActivity.this,
            R.layout.order_row, order_list_);
    orders_listview_.setAdapter(order_row_adapter_);

    // Request new updates from the server
    updateOrderInformation(-1);
}

public void updateOrders(InputStream new_order_stream) {
    Log.d(TAG, "Updating order UI");
    try {
        order_list_.parseFrom(new_order_stream);
    } catch (IOException e) {
        Log.e(TAG, "IOException" , e);
    }

    runOnUiThread(new Runnable() {
        public void run() {
            guiUpdateOrders();
        }
    });
}

private void guiUpdateOrders() {
    order_row_adapter_.notifyDataSetChanged();
    Log.d(TAG, "Dataset notified that it has changed. GUI update anytime now.");
}

但是,OrderRowAdapter 的 getView() 方法永远不会被调用。 ListView 永远不会更新。

【问题讨论】:

    标签: java android


    【解决方案1】:

    原来我的getView() 没有被调用的问题是因为它不可见。我的布局 xml 具有上部 TextViewfill_parent 的高度。因此,整个视图只有一个 TextView 可见。

    解决方案:检查相关布局的图形视图,确保 ListView 可见。

    【讨论】:

    • IMO 这是一个非常不明显的问题。特别是因为隐藏AdapterView 以显示Spinner 仍然是一种常见的范例,我可以看到这对很多人来说是讨厌的野鹅......
    【解决方案2】:

    确保BaseAdapter方法

    registerDataSetObserver(DataSetObserver observer) 
    unregisterDataSetObserver(DataSetObserver observer) 
    

    未被覆盖。

    【讨论】:

      【解决方案3】:

      要更改 ListView 的内容,您必须继续使用对 List 的相同引用。在这里,您正在创建另一个列表并将其分配给items_ 变量(它不包含列表本身,它只是存储对列表的引用的地方),但您的视图仍然具有对旧列表的引用。

      这应该可以代替items_ = new_order_list

      items_.clear();
      items_.addAll(new_order_list);
      

      编辑:

      为了更好地解释它,尝试创建一个名为 old_items 的新变量:

      public void setNewOrderList(List<Order> new_order_list)
      {
          Log.d(TAG, "New Order List available. Num items = " + new_order_list.size());
      
          List<Order> old_items = items_; // store the reference to the old list
          items_ = new_order_list;
      
          Log.d(TAG, "items_.size() = " + items_.size());
          Log.d(TAG, "old_items.size() = " + old_items.size()); // The old list still exists, and it's the one used by your ListView
      
          notifyDataSetChanged();
      }
      

      【讨论】:

      • 即便如此,如果getCount一直返回5,难道不应该调用我的getView方法吗?我尝试了你的建议,我在 java.util.Collections$UnmodifiableCollection.clear 得到了 java.lang.UnsupportedOperationException
      • 您的 getCount() 方法计算新列表中包含的项目,因为您替换了引用,而不是在内存中某处丢失的旧列表。我编辑了我的答案。
      • 您的异常意味着您的列表是只读的。你是如何创建它的?
      • 我有一个 protobuf 消息 OrderList,其中有多个订单。我的适配器假设提供一种在列表中可视化这些订单的方法。我使用返回只读副本的 OrderList.getOrdersList() 犯了一个错误。我已经修改了代码以直接包裹 OrderList。
      【解决方案4】:

      如果以上所有答案都不起作用,请尝试使用 invalidateViews()

      ListView.invalidateViews() 用于告诉 ListView 使其所有子项视图无效(重绘它们)。

      请注意,视图数不必与项目数相等。这是因为 ListView 会回收其项目视图并在您滚动时以智能的方式在屏幕上移动它们。

       listView.invalidateViews()
      

      我的示例实现,

                          lvitems.post(new Runnable() {
                              @Override
                              public void run() {
                                  lvitems.invalidateViews(); //invalidate old
                                  CustomAdapter customAdapter=new CustomAdapter(context, names, images); // load new data
                                  customAdapter.notifyDataSetChanged();// call notifydatasetChanged
                              }
                          });
      

      如果这个答案有任何错误,请纠正我的错误。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-11-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-09-28
        • 1970-01-01
        相关资源
        最近更新 更多