2012-02-22 17 views
8

Este problema se trata en esta pregunta Android: Wrong item checked when filtering listview. Para resumir el problema, al usar una vista de lista con un CursorAdapter y un filtro, los elementos seleccionados en una lista filtrada pierden su selección después de eliminar el filtro y, en su lugar, se seleccionan los elementos en esa posición en la lista no filtrada.Implementación de una vista de lista con selección múltiple con filtro utilizando un adaptador de cursor

Usando el ejemplo de código en la pregunta vinculada anterior, ¿dónde deberíamos poner el código para marcar las casillas de verificación? Creo que debería estar en el método getView() del CustomCursorAdapter, pero no estoy seguro. Además, ¿cómo accedemos al HashSet que contiene todos los Id seleccionados en la clase de adaptador personalizado, porque se inicializará y modificará en la actividad principal que contiene la lista?

Mi actividad aplicación del ListView

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

     Log.v(TAG, "onCreate called") ; 

     selectedIds = new ArrayList<String>() ; 
     selectedLines = new ArrayList<Integer>() ; 

     mDbHelper = new FriendsDbAdapter(this); 
     mDbHelper.open() ; 

     Log.v(TAG, "database opened") ; 

     Cursor c = mDbHelper.fetchAllFriends(); 
     startManagingCursor(c); 

     Log.v(TAG, "fetchAllFriends Over") ; 


     String[] from = new String[] {mDbHelper.KEY_NAME}; 
     int[] to = new int[] { R.id.text1 }; 

     final ListView listView = getListView(); 
     Log.d(TAG, "Got listView"); 

    // Now initialize the adapter and set it to display using our row 
     adapter = 
      new FriendsSimpleCursorAdapter(this, R.layout.selectfriendsrow, c, from, to); 

     Log.d(TAG, "we have got an adapter"); 
    // Initialize the filter-text box 
    //Code adapted from https://stackoverflow.com/questions/1737009/how-to-make-a-nice-looking-listview-filter-on-android 

     filterText = (EditText) findViewById(R.id.filtertext) ; 
     filterText.addTextChangedListener(filterTextWatcher) ; 

    /* Set the FilterQueryProvider, to run queries for choices 
    * that match the specified input. 
    * Code adapted from https://stackoverflow.com/questions/2002607/android-how-to-text-filter-a-listview-based-on-a-simplecursoradapter 
    */ 

     adapter.setFilterQueryProvider(new FilterQueryProvider() { 
      public Cursor runQuery(CharSequence constraint) { 
       // Search for friends whose names begin with the specified letters. 
       Log.v(TAG, "runQuery Constraint = " + constraint) ; 
       String selection = mDbHelper.KEY_NAME + " LIKE '%"+constraint+"%'"; 

       mDbHelper.open(); 
       Cursor c = mDbHelper.fetchFriendsWithSelection(
       (constraint != null ? constraint.toString() : null)); 
       return c; 
    } 
}); 




     setListAdapter(adapter); 

     Log.d(TAG, "setListAdapter worked") ; 


     listView.setItemsCanFocus(false); 
     listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); 

     // listView.setOnItemClickListener(mListener); 

     Button btn; 
     btn = (Button)findViewById(R.id.buttondone); 

     mDbHelper.close(); 

    } 


    @Override 
    protected void onListItemClick(ListView parent, View v, int position, long id) { 

     String item = (String) getListAdapter().getItem(position); 
     Toast.makeText(this, item + " selected", Toast.LENGTH_LONG).show(); 

     //gets the Bookmark ID of selected position 
     Cursor cursor = (Cursor)parent.getItemAtPosition(position); 
     String bookmarkID = cursor.getString(0); 

     Log.d(TAG, "mListener -> bookmarkID = " + bookmarkID); 

     Log.d(TAG, "mListener -> position = " + position); 

//  boolean currentlyChecked = checkedStates.get(position); 
//  checkedStates.set(position, !currentlyChecked); 


     if (!selectedIds.contains(bookmarkID)) { 

      selectedIds.add(bookmarkID); 
      selectedLines.add(position); 

     } else { 

      selectedIds.remove(bookmarkID); 
      selectedLines.remove(position); 


      } 

    } 



    private TextWatcher filterTextWatcher = new TextWatcher() { 

     public void afterTextChanged(Editable s) { 

     } 

     public void beforeTextChanged(CharSequence s, int start, int count, int after) { 

     } 

     public void onTextChanged(CharSequence s, int start, int before, int count) { 
      Log.v(TAG, "onTextChanged called. s = " + s); 
      adapter.getFilter().filter(s); 
     } 
    }; 

    @Override 
    protected void onDestroy() { 
     super.onDestroy(); 
     filterText.removeTextChangedListener(filterTextWatcher); 
    } 

Mi adaptador cursor personalizado:

public class FriendsSimpleCursorAdapter extends SimpleCursorAdapter implements Filterable { 

private static final String TAG = "FriendsSimpleCursorAdapter"; 
private final Context context ; 
private final String[] values ; 
private final int layout ; 
private final Cursor cursor ; 

static class ViewHolder { 
    public CheckedTextView checkedText ; 
} 

public FriendsSimpleCursorAdapter(Context context, int layout, Cursor c, 
     String[] from, int[] to) { 
    super(context, layout, c, from, to); 
    this.context = context ; 
    this.values = from ; 
    this.layout = layout ; 
    this.cursor = c ; 
    Log.d(TAG, "At the end of the constructor") ; 
} 

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    Log.d(TAG, "At the start of rowView. position = " + position) ; 
    View rowView = convertView ; 
    if(rowView == null) { 
     Log.d(TAG, "rowView = null"); 
     try { 
     LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     rowView = inflater.inflate(layout, parent, false); 
     Log.d(TAG, "rowView inflated. rowView = " + rowView); 
     ViewHolder viewHolder = new ViewHolder() ; 
     viewHolder.checkedText = (CheckedTextView) rowView.findViewById(R.id.text1) ; 
     rowView.setTag(viewHolder); 
     } 
     catch (Exception e) { 
      Log.e(TAG, "exception = " + e); 
     } 
    } 

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

    int nameCol = cursor.getColumnIndex(FriendsDbAdapter.KEY_NAME) ; 
    String name = cursor.getString(nameCol); 
    holder.checkedText.setText(name); 

    Log.d(TAG, "At the end of rowView"); 
    return rowView; 

} 

}

+0

Según este enlace, http://codereview.stackexchange.com/questions/1057/android-custom-cursoradapter-design, es mejor que anulemos newView y bindView. – rohitmishra

Respuesta

1

Lo que sí que lo resolvió:

act = cursor. c = el cursor interno simplecursoradapter.

en mi MainActivity:

(members) 
static ArrayList<Boolean> checkedStates = new ArrayList<Boolean>(); 
static HashSet<String> selectedIds = new HashSet<String>(); 
static HashSet<Integer> selectedLines = new HashSet<Integer>(); 

en el onItemClickListener Listview:

if (!selectedIds.contains(bookmarkID)) { 

    selectedIds.add(bookmarkID); 
    selectedLines.add(position); 


} else { 

    selectedIds.remove(bookmarkID); 
    selectedLines.remove(position); 



if (selectedIds.isEmpty()) { 
    //clear everything 
     selectedIds.clear(); 
     checkedStates.clear();  
     selectedLines.clear(); 

     //refill checkedStates to avoid force close bug - out of bounds 
     if (cur.moveToFirst()) { 
      while (!cur.isAfterLast()) {  
       MainActivity.checkedStates.add(false); 

       cur.moveToNext(); 
      } 
     }      

} 

En el SimpleCursorAdapter he añadido (tanto en getView):

// fill the checkedStates array with amount of bookmarks (prevent OutOfBounds Force close) 
     if (c.moveToFirst()) { 
      while (!c.isAfterLast()) { 
       MainActivity.checkedStates.add(false); 
       c.moveToNext(); 
      } 
     } 

y:

String bookmarkID = c.getString(0); 
     CheckedTextView markedItem = (CheckedTextView) row.findViewById(R.id.btitle); 
     if (MainActivity.selectedIds.contains(new String(bookmarkID))) { 
      markedItem.setChecked(true); 
      MainActivity.selectedLines.add(pos); 

     } else { 
      markedItem.setChecked(false); 
      MainActivity.selectedLines.remove(pos); 
     } 

Espero que esto ayude ... Usted, por supuesto necesario para ajustarlo a sus necesidades.

EDIT:

descargados FB SDK, no podía conseguir pasar a la entrada FB. tienes un error que no te da un access_token válido si la aplicación FB está instalada en el dispositivo. Se eliminó la aplicación FB y se obtuvo un FC en getFriends(). Lo resolvió envolviendo su alcance con runOnUiThread(new Runnable...).

El error que obtiene no tiene nada que ver con un mal filtrado, estados de casilla de verificación incorrectos ... Lo obtiene porque está tratando de acceder al cursor antes de consultarlo (ya cerrado). Parece que está cerrando el cursor antes de que el adaptador lo esté utilizando. Verificado al agregar:

mDbHelper = new FriendsDbAdapter(context); 

     mDbHelper.open() ; 
     cursor = mDbHelper.fetchAllFriends(); 

al alcance de getView en SelectFriendsAdapter.

Después de agregar esto, no será FC y podrá comenzar a cuidar su filtro. Asegúrese de que el cursor no esté cerrado y, básicamente, si lo está administrando con startManagingCursor(), no es necesario cerrarlo manualmente.

¡Espero que lo puedas sacar de aquí!

+0

Muchas gracias por su ayuda. Todavía estoy enfrentando problemas en setFilterQueryProvider. Usar el mismo helper de base de datos que el usado para SimpleCursorAdapter me está dando un "Error de Statement in fillWindow()" En mi lista de actividad, he usado una instancia de mDbHelper que es DatabaseHelper. Hago una llamada a c = mDbHelper.fetchAllFriends() seguido de un startManagingCursor() en la onCreate de mi listActivity. ¿Debo declarar una nueva instancia de mDbHelper para la llamada en runQuery()? No puedo encontrar cuál es la forma preferida de lidiar con esto. – rohitmishra

+0

@movingahead No estoy seguro de entender cómo ayudarlo y cómo su pregunta actual está relacionada con lo que describió en la publicación OP, PERO, después del error que recibe, parece que la manera correcta es crear una instancia del mDbHelper en el onCreate (nuevo mDbHelper() o lo que sea) y luego llame a fetchFriends. Ver aquí: 1. http://stackoverflow.com/questions/4195089/what-does-invalid-statement-in-fillwindow-in-android-cursor-mean 2. http://stackoverflow.com/questions/4258493/invalid-statement-in-fillwindow-in-android 3. http://stackoverflow.com/questions/9049542/invalid-statement-in-fillwindow –

+0

He seguido todos los enlaces que ha señalado. Estoy recibiendo uno u otro error de cursor. De todas formas, gracias por la ayuda. – rohitmishra

Cuestiones relacionadas