2012-10-31 10 views
5

Sto utilizzando un ArrayAdapter personalizzato per impostare l'adattatore su un AutocompleteTextView (AddressAdapter estende ArrayAdapter).IllegalStateException: il contenuto dell'adattatore è cambiato ma ListView non ha ricevuto una notifica

public class AutoCompleteAdapter extends ArrayAdapter<String> implements Filterable { 
private ArrayList<String> mData; 
ArrayList<String> listTempPrefix = new ArrayList<String>(); 
ArrayList<String> listTemp = new ArrayList<String>(); 
String valueText; 
String[] words; 
String ulcase; 

public AutoCompleteAdapter(Context context, int textViewResourceId, ArrayList<String> bS) { 
    super(context, textViewResourceId); 
    mData = bS;//new ArrayList<String>(); 
} 

@Override 
public int getCount() 
{ 
    synchronized (listTempPrefix) 
    { 
     return listTempPrefix.size(); 
    } 
} 

@Override 
public String getItem(int index) 
{ 
    synchronized (listTempPrefix) 
    { 
     try { 
      //Log.e("Error", listTempPrefix.get(index)); 
      return listTempPrefix.get(index); 
     } catch(IndexOutOfBoundsException e) { 
      Log.e("Error", "IndexOutOfBoundsException"); 
      return ""; 
     } 
    } 

} 

@Override 
public Filter getFilter() 
{ 
    Filter myFilter = new Filter() { 
     @Override 
     protected FilterResults performFiltering(CharSequence constraint) 
     { 

      FilterResults filterResults = new FilterResults(); 
      synchronized (filterResults) 
      { 
       listTempPrefix.clear(); 
       listTemp.clear(); 
       //Log.e("1", "1"); 

       try { 
       if(constraint != null) { 
        // A class that queries a web API, parses the data and returns an ArrayList<Style> 
        //StyleFetcher fetcher = new StyleFetcher(); 
        //try { 
         //mData = fetcher.retrieveResults(constraint.toString()); 
        //} 
        //catch(Exception e) {} 
        // Now assign the values and count to the FilterResults object 


        for(String value: mData) { 
         valueText = value.toLowerCase(); 

         //System.out.println("constraintH - " + constraint); 

         constraint.toString().toLowerCase(); 
         ulcase = constraint.toString().toLowerCase(); 
         //System.out.println("ulcase - " + ulcase); 

         if (valueText.startsWith(ulcase)) { 
          listTempPrefix.add(value); 
         } else { 
          words = valueText.split(" "); 
          //final int wordCount = words.length; 

          // Start at index 0, in case valueText starts with space(s) 
          for (int k = 0; k < words.length; k++) { 
           if (words[k].startsWith(ulcase)) { 
            listTemp.add(value); 
            break; 
           } 
          } 
         } 

         ///listTemp.add(mData.get(i)); 
         //filterResults.count = mData.size(); 
      //   System.out.println("mData" + i + mData.get(i)); 
        } 
        //Log.e("2", "2"); 
      //  System.out.println("size " + listTemp.size() + " value" + listTemp); 

        listTempPrefix.addAll(listTemp); 

        filterResults.values = listTempPrefix; 

        filterResults.count = listTempPrefix.size(); 
        //System.out.println("size " + filterResults.count + " value" + filterResults.values); 

        //System.out.println("constraint" + constraint); 

       } 
       } catch (Exception e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
        } 
       return filterResults; 
      } 
     } 

     @Override 
     protected void publishResults(CharSequence contraint, FilterResults filterResults) 
     { 
      synchronized (filterResults) 
      { 
       if(filterResults != null && filterResults.count > 0) { 
       notifyDataSetChanged(); 
       //Log.e("notifyDataSetChanged", "notifyDataSetChanged"); 
       } 
       else { 
        notifyDataSetInvalidated(); 
        //Log.e("notifyDataSetInvalidated", "notifyDataSetInvalidated"); 
       } 
      } 
     } 
    }; 
    return myFilter; 
} 

}

Quello che ho ottenuto a volte: si prega di notare, accade davvero raramente. Ma mi piacerebbe sbarazzarmi completamente di questo bug. Ecco stacktrace parziale:

java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(-1, class android.widget.AutoCompleteTextView$DropDownListView) with Adapter(class com.example.test.AutoCompleteAdapter)]. 

Il problema forse che l'ingresso rapido da keybord, metodo notifyDataSetChanged() call issn't. Ma non sono sicuro.

risposta

0

è necessario chiamare il metodo notifyDataSetChanged() non appena il set di dati (ArrayList, Array, Cursor, ecc,) appoggiando la vostra Adapter modifiche. Altrimenti finirai con questo Exception.

+0

Potresti scrivere un campione di come ottenere l'IllegalStateException? – user1528799

7

Si sta modificando l'array listTempPrefix su performFiltering (utilizzando clear e addAll), quindi è necessario chiamare notifyDataSetChanged per evitare questa eccezione.

Ma performFiltering non viene chiamato sul thread dell'interfaccia utente, pertanto anche chiamando notifyDataSetChanged si genera un'eccezione.

Il modo migliore per risolvere questo problema è modificare l'array listTempPrefix all'interno di publishResults e quindi chiamare notifyDataSetChanged.

Rimuovere le modifiche apportate a listTempPrefix dal metodo performFiltering (potrebbe essere necessario creare un array temporaneo in base alla logica del filtro).

Su publishResults, aggiornare l'array listTempPrefix con i valori contenuti in filterResults e chiamare notifyDataSetChanged.

Ecco un exemple in base al codice:

@Override 
public Filter getFilter() 
{ 
    Filter myFilter = new Filter() { 
     @Override 
     protected FilterResults performFiltering(CharSequence constraint) 
     { 

      FilterResults filterResults = new FilterResults(); 
      synchronized (filterResults) 
      { 
       //listTempPrefix.clear(); // Don't change listTempPrefix here 
       ... 
         ulcase = constraint.toString().toLowerCase(); 
         //System.out.println("ulcase - " + ulcase); 

         if (valueText.startsWith(ulcase)) { 
          //listTempPrefix.add(value); // Don't change listTempPrefix 
          // To keep your logic you might need an aux array 
          // for this part 
         } else { 
          ... 
         } 

        //listTempPrefix.addAll(listTemp); // Don't change it 

        filterResults.values = listTempPrefix; // No problem here 

        filterResults.count = listTempPrefix.size(); // No problem here 
        //System.out.println("size " + filterResults.count + " value" + filterResults.values); 

        //System.out.println("constraint" + constraint); 

       } 
       } catch (Exception e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
        } 
       return filterResults; 
      } 
     } 

     @Override 
     protected void publishResults(CharSequence contraint, FilterResults filterResults) 
     { 
      // At this point, make the changes you need to listTempPrefix 
      // using filterResults.values 
      synchronized (filterResults) 
      { 
       if(filterResults != null && filterResults.count > 0) { 
       notifyDataSetChanged(); 
       //Log.e("notifyDataSetChanged", "notifyDataSetChanged"); 
       } 
       else { 
        notifyDataSetInvalidated(); 
        //Log.e("notifyDataSetInvalidated", "notifyDataSetInvalidated"); 
       } 
      } 
     } 
    }; 
    return myFilter; 
} 
+0

Non conosco molto l'inglese. Non ho compreso appieno il tuo punto, puoi scrivere un campione. – user1528799

+0

Modificato la mia risposta con un po 'di codice, vedere se questo aiuta – Marcelo

+0

Il tuo esempio non aiuta ( – user1528799

9

Modifica publishResults a

@Override 
protected void publishResults(final CharSequence contraint, final FilterResults filterResults) { 
    listTempPrefix = (List) results.values; 
    if(filterResults != null && filterResults.count > 0) { 
     notifyDataSetChanged(); 
    } else { 
     notifyDataSetInvalidated(); 
    } 
} 

In questo modo il filo GUI aggiorna i risultati invece di performFiltering che viene eseguito in un thread in background.

riferimenti Rimuovere listTempPrefix da performFiltering e utilizzare una variabile locale lì per memorizzare i risultati e restituirli attraverso FilterResults

+1

Risposta perfetta, grazie! Risolto il problema di IllegalStateException con il codice demo che Google ha fornito per il completamento automatico dei luoghi su https://developers.google.com/places/training/autocomplete-android – Price

Problemi correlati