2012-10-31 28 views
5

我正在使用自定義ArrayAdapter在AutocompleteTextView(AddressAdapter extends ArrayAdapter)上設置適配器。IllegalStateException:適配器的內容已更改,但ListView未收到通知

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

}

我有時會遇到:請注意,它真的發生很少。但我想徹底擺脫這個錯誤。下面是局部堆棧跟蹤:

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

問題也許從keybord快速輸入,方法notifyDataSetChanged()issn't呼叫。但是我不確定。

回答

0

你必須儘快數據集(ArrayListArrayCursor等)調用notifyDataSetChanged()方法備份您的Adapter變化。否則你會以這個Exception結束。

+0

歸還你能寫一個樣品如何獲得IllegalStateException異常? – user1528799

7

您正在更改performFiltering上的listTempPrefix數組(使用clear和addAll),因此您需要調用notifyDataSetChanged以避免此異常。

但是performFiltering未在UI線程中調用,因此調用notifyDataSetChanged也會引發異常。

解決此問題的最佳方法是更改​​publishResults中的listTempPrefix數組,然後調用notifyDataSetChanged

performFiltering方法中刪除對listTempPrefix所做的更改(您可能需要根據過濾器邏輯創建臨時數組)。

publishResults上,使用filterResults中包含的值更新您的listTempPrefix數組,並調用notifyDataSetChanged

這是基於你的代碼爲例:

@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

我不太懂英文。我沒有完全理解你的觀點,你可以寫一個樣本。 – user1528799

+0

用一些代碼編輯我的答案,看看是否有幫助 – Marcelo

+0

你的榜樣沒有幫助( – user1528799

9

變化publishResults到

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

這樣GUI線程更新的結果,而不是performFiltering它運行在後臺線程。

從performFiltering刪除listTempPrefix引用和使用局部變量有存儲結果,並通過FilterResults

+1

完美答案,謝謝!解決了IllegalStateException問題,Google提供的Places Autocompletion演示代碼位於https://developers.google.com/places/training/autocomplete-android – Price

相關問題