2011-12-06 73 views
12

我有一个自定义适配器,可视化订单列表中的每一行。BaseAdapter notifyDatasetChanged()被调用,但getView()永远不会被调用

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

从Web服务查询订单的新名单后,我想更新ListView控件的内容,所以我有我的活动并更新调用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从不更新。

回答

12

原来问题我的getView()未被调用是因为它不可见。我的布局xml的高度为TextView,其高度为fill_parent。因此整个视图只能看到单个的TextView

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

+0

IMO这是一个非常不明显的问题。特别是因为隐藏'AdapterView'来显示一个'Spinner'仍然是一个常见的范例,我可以看到这是很多人讨厌的野鹅... – alexgophermix

1

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

代替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(); 
} 
+0

即使如此,如果getCount保持返回5,我的getView方法不应该被调用吗?我尝试了你的建议,并在java.util.Collections $ UnmodifiableCollection.clear –

+0

处得到了java.lang.UnsupportedOperationException。'getCount()'方法计算新列表中包含的项目,因为你替换了引用,而不是旧的记忆中某处丢失。我编辑了我的答案。 – Dalmas

+0

你的例外意味着你的列表是只读的。你如何创建它? – Dalmas

2

确保BaseAdapter方法

registerDataSetObserver(DataSetObserver observer) 
unregisterDataSetObserver(DataSetObserver observer) 

不覆盖。

0

如果以上问题的答案不工作尝试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 
         } 
        }); 

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

相关问题