Подтвердить что ты не робот

Ошибка использования notifyDataSetChanged в аэродромном массиве

11-06 19: 52: 25.958: E/AndroidRuntime (29609): java.lang.IllegalStateException: содержимое адаптера имеет изменено, но ListView не получил уведомление. Убедитесь, что содержимое вашего адаптера не изменяется из фонового потока, но только из потока пользовательского интерфейса. [в ListView (-1, класс android.widget.ListPopupWindow $DropDownListView) с адаптером (класс com.example.parkfoxxlight_android.PlacesAutoCompleteAdapter)]

Полный журнал: http://pastebin.com/Hx7k28Rm

Полный код адаптера: http://pastebin.com/TfH1bXE3 Я использую пример из https://developers.google.com/places/training/autocomplete-android, и он имеет вполне стандартный код, поэтому кажется, что в коде google есть ошибка?

Приложение вызывается только иногда с указанным выше сообщением об ошибке.

protected void publishResults(CharSequence constraint,
        FilterResults results) {

    if (results != null && results.count > 0) {
        notifyDataSetChanged();
    } else {
        notifyDataSetInvalidated();
    }
}

Активность http://pastebin.com/FYzYtvXY:

public class CityActivity extends Activity{

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.city);

            AutoCompleteTextView autoCompView = (AutoCompleteTextView) findViewById(R.id.autocomplete_city);

            PlacesAutoCompleteAdapter ad = new PlacesAutoCompleteAdapter(this);
            ProgressBar b = (ProgressBar)findViewById(R.id.progressBar1);
            ad.setLoadingIndicator(b);

            autoCompView.setAdapter(ad);
        }
}

Есть идеи, как это исправить? Я на Android 4.3.

4b9b3361

Ответ 1

Метод Filter performFiltering() работает в фоновом потоке и из этого метода вы меняете resultList, на котором основан ваш адаптер. Если вы измените этот список данных, и в это время ListView получит доступ к адаптеру, он увидит, что что-то изменилось без его ведома (и это не понравится). Вам следует избегать использования resultList в методе performFiltering и просто создать новый временный список:

// in the performFiltering method which runs on a background thread:
@Override
protected FilterResults performFiltering(CharSequence constraint) {
     FilterResults filterResults = new FilterResults();
     ArrayList<String> queryResults;
     if (constraint != null && constraint.length() > 0) {
         queryResults = autocomplete(constraint);
     } else {
         queryResults = new ArrayList<String>(); // empty list/no suggestions showing if there no valid constraint
     }
     filterResults.values = queryResults;
     filterResults.count = queryResults.size();
     return filterResults; // ## Heading ##
}

private List<String> autocomplete(String input) {
   // don't use the here the resultList List on which the adapter is based!
   // some custom code to get items from http connection
     ArrayList<String> queryResults = new ArrayList<String>(); // new list
     queryResults.add("Some String");
     return queryResults;
}

@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
     // update the data with the new set of suggestions
     resultList = (ArrayList<String>)results.values;
     if (results.count > 0) {
         notifyDataSetChanged();
     } else {
         notifyDataSetInvalidated();
     }
}

Ответ 2

Попробуйте это (просто догадка):

@Override
    public Filter getFilter() {
        Filter filter = new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults filterResults = new FilterResults();
                if (constraint != null) {
                    ArrayList list = autocomplete(constraint.toString());
                    if (list != null) {
                        filterResults.values = list;
                        filterResults.count = list.size();
                    }
                }
                return filterResults;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                if (results != null && results.count > 0) {
                    //change the underlying data immediately before notifying UI                        
                    resultList = (ArrayList)results.values; 
                    notifyDataSetChanged();
                }
                else {
                    notifyDataSetInvalidated();
                }
            }};
        return filter;
    }