2012-10-31 10 views
5

Używam niestandardowego ArrayAdapter do ustawienia adaptera w AutocompleteTextView (AddressAdapter rozszerza ArrayAdapter).IllegalStateException: Zawartość adaptera została zmieniona, ale ListView nie otrzymał powiadomienia.

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

}

Co mam czasami: proszę zauważyć, zdarza się naprawdę rzadko. Ale chciałbym całkowicie pozbyć się tego błędu. Oto częściowy StackTrace:

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)]. 

Problem może fakt, że szybka wejście od keybord, metoda notifyDataSetChanged() wezwanie issn't. Ale nie jestem pewien.

Odpowiedz

0

Musisz wywołać metodę notifyDataSetChanged() jak najszybciej zbioru danych (ArrayList, Array, Cursor itp,) kopii swoich Adapter zmian. Albo skończysz z tym Exception.

+0

można napisać próbkę jak uzyskać IllegalStateException? – user1528799

7

Zmieniasz tablicę listTempPrefix na performFiltering (używając polecenia clear i addAll), więc aby uniknąć tego wyjątku, musisz zadzwonić pod numer notifyDataSetChanged.

Ale performFiltering nie jest wywoływany w wątku interfejsu użytkownika, dlatego wywołanie notifyDataSetChanged spowoduje również zgłoszenie wyjątku.

Najlepszym sposobem rozwiązania tego problemu jest zmiana tablicy listTempPrefix wewnątrz publishResults, a następnie wywołanie notifyDataSetChanged.

Usuń zmiany wprowadzone do listTempPrefix z metody performFiltering (może być konieczne utworzenie tablicy tymczasowej w zależności od logiki filtra).

Na publishResults zaktualizuj tablicę listTempPrefix wartościami podanymi na filterResults i zadzwoń pod numer notifyDataSetChanged.

Oto exemple oparty na kodzie:

@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

Nie wiem zbyt dobrze po angielsku. Nie do końca rozumiem twój punkt, możesz napisać próbkę. – user1528799

+0

Zmieniono moją odpowiedź za pomocą kodu, zobacz, czy to pomaga – Marcelo

+0

Twój przykład nie pomaga ( – user1528799

9

Zmiany publishResults do

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

ten sposób wątek GUI aktualizuje wyniki zamiast performFiltering która biegnie w wątku tła.

referencje Usuń listTempPrefix z performFiltering i użyć zmiennej lokalnej jest do przechowywania wyników i ich zwrotu przez FilterResults

+1

Doskonała odpowiedź, dzięki! Rozwiązany problem IllegalStateException z kodem demo, który Google udostępnił Autouzupełnianie Miejsc na https://developers.google.com/places/training/autocomplete-android – Price

Powiązane problemy