2012-02-22 15 views
8

Questo problema è discusso in questa domanda Android: Wrong item checked when filtering listview. Per riassumere il problema, quando si utilizza un listview con un CursorAdapter e un filtro, gli elementi selezionati in un elenco filtrato perdono la loro selezione dopo che il filtro è stato rimosso e, invece, gli elementi in quella posizione nell'elenco non filtrato vengono selezionati.Implementazione di un listview con selezione multipla con filtro utilizzando un adattatore per cursori

Utilizzando l'esempio di codice nella domanda collegata sopra, dove dovremmo inserire il codice per contrassegnare le caselle di controllo. Credo che dovrebbe essere nel metodo getView() di CustomCursorAdapter, ma non sono sicuro. Inoltre, come possiamo accedere a HashSet tenendo tutti gli ID selezionati nella classe dell'adattatore personalizzato, poiché verrà inizializzato e modificato nell'attività principale che contiene l'elenco.

La mia attività di attuazione 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); 
    } 

mio adattatore cursore personalizzato:

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

In base a questo collegamento, http://codereview.stackexchange.com/questions/1057/android-custom-cursoradapter-design, è preferibile ignorare newView e bindView. – rohitmishra

risposta

1

Quello che ho fatto che risolto:

cur = cursore. c = il cursore interno del cursore simplecursoradapter.

nel mio MainActivity:

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

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

} 

Nel SimpleCursorAdapter ho aggiunto (sia in 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(); 
      } 
     } 

e:

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

Spero che questo aiuti ... avrete ovviamente bisogno di adattarlo alle proprie esigenze.

EDIT:

scaricato FB SDK, non ha potuto ottenere passare il login FB. si ha un bug in cui non si ottiene un access_token valido se l'app FB è installata sul dispositivo. Rimosso l'app FB e ottenuto un FC in getFriends(). Risolto il problema avvolgendo il suo ambito con runOnUiThread(new Runnable...).

L'errore che si ottiene non ha nulla a che fare con un filtro errato, stati di casella di controllo non validi ... Si ottiene perché si sta tentando di accedere al cursore prima di eseguire una query (già chiuso). Sembra che tu stia chiudendo il cursore prima che l'adattatore lo stia usando. Verificato con l'aggiunta:

mDbHelper = new FriendsDbAdapter(context); 

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

nello scope getView in SelectFriendsAdapter.

Dopo aver aggiunto questo, non sarà FC e si può iniziare a prendersi cura del filtro. Assicurati che il cursore non sia chiuso e in pratica se lo stai gestendo con startManagingCursor(), non è necessario chiuderlo manualmente.

Spero che tu possa portarlo da qui!

+0

Grazie mille per il tuo aiuto. Sto ancora affrontando problemi in setFilterQueryProvider. Utilizzando lo stesso helper del database usato per SimpleCursorAdapter mi viene fornita una "Istruzione non valida nell'errore fillWindow()" Nella mia lista, ho usato un'istanza di mDbHelper che è il mio DatabaseHelper. Faccio una chiamata a c = mDbHelper.fetchAllFriends() seguito da un startManagingCursor() nel onCreate della mia listaAttività. Devo dichiarare una nuova istanza di mDbHelper per la chiamata in runQuery()? Non sono in grado di trovare qual è il modo preferito per affrontare questo. – rohitmishra

+0

@movingahead Non sono sicuro di capire come aiutarti e in che modo la tua domanda corrente è correlata a ciò che hai descritto nel post OP, MA, seguendo l'errore che ricevi, sembra che il modo giusto sia di istanziare mDbHelper in onCreate (nuovo mDbHelper() o qualsiasi altra cosa) e quindi chiama fetchFriends. Vedere qui: 1. http://stackoverflow.com/questions/4195089/che-segue-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

Ho seguito tutti i collegamenti che hai indicato. Sto ottenendo uno o un altro errore del cursore. Comunque, grazie per l'aiuto. – rohitmishra

Problemi correlati