2011-10-12 23 views
8

Tengo una actividad de Android en la que tengo un ListView vinculado a un ArrayAdapter personalizado. Cada fila de ListView tiene dos campos EditText (numéricos).Android - EditTexts dentro de ListView vinculado a Custom ArrayAdapter - realizando un seguimiento de los cambios

El ArrayAdapter se llena inicialmente de una base de datos SQLite. Sin embargo, el usuario puede agregar una fila al final de ListView, o (al presionar durante mucho tiempo en una fila) eliminar cualquier fila en el ListView. Cuando presionan el botón "Guardar", sus cambios se mantienen.

Realizo un seguimiento de los cambios tal como están hechos adjuntando un CustomTextWatcher para el evento AfterTextChanged() a cada EditText en el método getView() de ArrayAdapter (pasando el EditText y el objeto correspondiente en la lista de elementos de ArrayAdapter) luego estableciendo la propiedad de coincidencia de ese objeto con el contenido de EditText. Esto es para que al guardar pueda simplemente iterar a través de la lista de objetos subyacente y hacer los cambios de base de datos apropiados, sabiendo que la lista de objetos está actualizada.

Código

para la clase adaptador y el CustomTextWatcher:

private class CustomAdapter extends ArrayAdapter<DataItem> { 
    private ArrayList<DataItem> items; 

    public CustomAdapter(Context context, int textViewResourceId, ArrayList<DataItem> items) { 
     super(context, textViewResourceId, items); 
     this.items = items; 
} 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
      View v = convertView; 

      DataItem wed = items.get(position); 

      if (v == null) { 
       LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
       v = vi.inflate(R.layout.log_exercise_row, null); 
      } 

      if(wed != null) 
      { 
        EditText text1 = (EditText) v.findViewById(R.id.text1); 
        EditText text2 = (EditText) v.findViewById(R.id.text2); 

       text1.addTextChangedListener(new CustomTextWatcher(text1,wed)); 
       text2.addTextChangedListener(new CustomTextWatcher(text2,wed)); 


       int weight = wed.getWeight(); 

       if(weight != -1) 
       { 
        text1.setText(weight+""); 
       } 


       int reps = wed.getReps(); 

       if(reps != -1) 
       { 
        text2.setText(reps+""); 
       } 


      } 

      return v; 
    } 

private class CustomTextWatcher implements TextWatcher { 

    private EditText EditText; 
    private DataItem item; 

    public CustomTextWatcher(EditText e, DataItem item) 
    { 
     this.EditText = e; 
     this.item = item; 
    } 

    @Override 
    public void afterTextChanged(Editable arg0) { 

     String text = arg0.toString(); 

     if(text != null && text.length() > 0) 
     { 
      int val; 

      try 
      { 
       val =Integer.parseInt(text); 
      } 

      catch(NumberFormatException e) 
      { 
       val=-1; 
      } 

      if(EditText.getId()==R.id.weightEditText) 
      { 
       item.setWeight(val); 
      } 

      else if(EditText.getId()==R.id.repsEditText) 
      { 
       item.setRepetitions(val); 
      } 
     } 
    } 

Todo esto funciona bien, excepto cuando se añaden o eliminan elementos cuando la duplicación no deseada del contenido EditarTexto sucede.

Para ilustrar con un ejemplo:

de inicio con 3 filas, de EditarTexto todas vacías
En la fila 2, introduzca '5' '6'
Haga clic en 'Más' -> Añade una fila (vacío) al final. Ahora 4 filas.
Eliminar la última fila-> 3 filas mostradas, PERO las filas 2 y 3 ahora muestran '5', '6' -> ???????

Parece que la posición relativa de los objetos EditText dentro de ListView no es estable después de volver a vincular, lo que está causando el problema. P.ej. El objeto EditText 'X' comienza en la posición 3, luego, después de una nueva vinculación, está en la posición 1, pero todavía tiene un CustomTextWatcher asociado al objeto de datos en la posición 3. El otro problema es el hecho de que addTextChangedListener() no afecta los TextWatchers ya están adjuntos a EditText.

Soy bastante nuevo en Android, por lo que no estoy seguro de si hay un mejor enfoque para resolver mi problema. Cualquier ayuda es apreciada.

Respuesta

9

Parece que una clase personalizada ('ViewHolder') era lo que necesitaba para mantener las referencias entre un EditText y su objeto de datos asociado correctamente sincronizadas en cada 'enlace' de los datos. Además, colocar las llamadas de escucha de eventos cuando el objeto convertView era nulo en el método getView() significaba que solo se agregaba un oyente por objeto EditText.

Gracias a http://www.vogella.de/articles/AndroidListView/article.html#listsactivity por orientarme en la dirección correcta.

public class CustomAdapter extends ArrayAdapter<DataItem> { 
private ArrayList<DataItem> items; 
private Activity Context; 

public CustomAdapter(Activity context, int textViewResourceId, ArrayList<DataItem> items) { 
    super(context, textViewResourceId, items); 
    this.items = items; 
    this.Context = context; 
} 

static class ViewHolder { 
    protected EditText weight; 
    protected EditText reps; 

} 

public View getView(int position, View convertView, ViewGroup parent) { 
     View v = convertView; 

     DataItem wed = items.get(position); 


     if (v == null) { 
      LayoutInflater inflator = Context.getLayoutInflater(); 
      v = inflator.inflate(R.layout.log_exercise_row, null); 
      final ViewHolder viewHolder = new ViewHolder(); 
      viewHolder.text1 = (EditText) v.findViewById(R.id.text1); 
      viewHolder.text2 = (EditText) v.findViewById(R.id.text2); 


      viewHolder.text1.addTextChangedListener(new CustomTextWatcher(viewHolder, viewHolder.text1)); 
      viewHolder.text2.addTextChangedListener(new CustomTextWatcher(viewHolder, viewHolder.text2)); 

      v.setTag(viewHolder); 
      viewHolder.text1.setTag(wed); 
      viewHolder.text2.setTag(wed); 

     } 

     else 
     { 
      ViewHolder holder = (ViewHolder) v.getTag(); 
      holder.text1.setTag(wed); 
      holder.text2.setTag(wed); 
     } 

     ViewHolder holder = (ViewHolder) v.getTag(); 

     // set values 

     if(wed.getWeight() != -1) 
     { 
      holder.text1.setText(wed.getWeight()+""); 
     } 

     else 
     { 
      holder.weight.setText(""); 
     } 

     if(wed.getRepetitions() != -1) 
     { 
      holder.text2.setText(wed.getRepetitions()+""); 
     } 

     else 
     { 
      holder.reps.setText(""); 
     } 

     return v; 
} 
+0

digamos que tengo un número dinámico de niños, y todos los niños tienen su propio texto de edición. ¿Cómo podemos crear y establecer observadores de texto iguales a los niños? Gracias – yfsx

Cuestiones relacionadas