2011-12-06 20 views
12

Tengo un adaptador personalizado que visualiza cada fila en la lista de Pedidos.BaseAdapter notifyDatasetChanged() llamado pero getView() nunca se llama

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

Después de la consulta nueva lista de órdenes de un servicio web, quiero actualizar el contenido del ListView, así que tengo mi actividad hace la actualización antes de llamar 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."); 
} 

Pero, el método getView() de OrderRowAdapter nunca se llama. ListView nunca se actualiza.

Respuesta

12

Resulta que el problema con mi getView() al que no se ha llamado es porque no está visible. Mi diseño xml tiene la parte superior TextView con fill_parent para su altura. Por lo tanto, toda la vista solo tiene ese único TextView visible.

Solución: compruebe la vista gráfica del diseño en cuestión para asegurarse de que ListView esté visible.

+0

IMO este es un problema muy obvio. Especialmente porque ocultar un 'AdapterView' para mostrar un' Spinner' sigue siendo un paradigma común, puedo ver que este es ese ganso salvaje molesto para mucha gente ... – alexgophermix

1

Para cambiar el contenido de su ListView, debe seguir usando la misma referencia a la Lista. Aquí está creando otra lista y asignándola a la variable items_ (que no contiene la lista en sí misma, es solo un lugar para almacenar una referencia a una Lista), pero su Vista todavía tiene una referencia a la lista anterior.

En lugar de items_ = new_order_list esto debería funcionar:

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

EDIT:

Para explicarlo mejor, intenta crear una nueva variable denominada 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

Aun así, ¿no debería invocarse mi método getView si getCount sigue mostrando 5? Intenté tu sugerencia y recibí java.lang.UnsupportedOperationException en java.util.Collections $ UnmodifiableCollection.clear –

+0

Tu método 'getCount()' cuenta los elementos contenidos en tu nueva lista ya que reemplazaste la referencia, no la anterior, que es perdido en algún lugar de la memoria. Edité mi respuesta. – Dalmas

+0

Su excepción significa que su lista es de solo lectura. ¿Cómo lo creas? – Dalmas

2

Asegúrese de que los métodos BaseAdapter

registerDataSetObserver(DataSetObserver observer) 
unregisterDataSetObserver(DataSetObserver observer) 

no se anulan.

0

Si todas las respuestas anteriores no intento con invalidateViews de trabajo()

ListView.invalidateViews() se usa para decirle al ListView para invalidar todas sus vistas de elementos hijo (redibujarlo).

Tenga en cuenta que no es necesario que haya un número igual de vistas que los elementos. Esto se debe a que ListView recicla sus vistas de elementos y las mueve alrededor de la pantalla de forma inteligente mientras se desplaza.

listView.invalidateViews() 

Mi implementación de ejemplo,

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

Si algún error en esta respuesta por favor corregir mis errores.

Cuestiones relacionadas