Search code examples
javaandroidandroid-asynctaskautocompletetextviewillegalstateexception

AutoCompleteTextView randomly throws IllegalStateException


I've been receiving a few Play Store reports of my android app crashing due to IllegalStateException in my AutoCompleteTextView. However, I've never been able to recreate the issue myself. The AutoCompleteTextView uses custom filtering, and I more or less followed the codes here: Custom filtering in AutoCompleteTextView not working

I've done some research on the problem, found this as one of the results: How to resolve "The content of the adapter has changed but ListView did not receive a notification” exception but still can't work out what's wrong with my code. I can't even figure out what's causing the exception to occur, it just occurs randomly, though most of the time it doesn't occur. What's more frustrating, the exception stack trace doesn't point out which line of my code that is causing the exception.

Here is the exception stack trace:

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 transponders.transmob.JourneyPlanner$LocationAdapter)]
at android.widget.ListView.layoutChildren(ListView.java:1541)
at android.widget.AbsListView.onLayout(AbsListView.java:1428)
at android.view.View.layout(View.java:7228)
at android.widget.FrameLayout.onLayout(FrameLayout.java:338)
at android.view.View.layout(View.java:7228)
at android.view.ViewRoot.performTraversals(ViewRoot.java:1148)
at android.view.ViewRoot.handleMessage(ViewRoot.java:1868)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3691)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:907)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:665)
at dalvik.system.NativeStart.main(Native Method)

And here is my custom filter code in the custom adapter class:

        @Override
        public Filter getFilter() 
        {
            Filter filter = new Filter(){
                  @Override
                  protected FilterResults performFiltering(CharSequence constraint)
                  {
                      locations.clear();
                      FilterResults results = new FilterResults();
                      String typedText = ownerACTV.getText().toString();

                      try
                      {
                          Log.d("performFiltering", "TYPED TEXT LENGTH: " + typedText.length());
                          if(!typedText.equals("Current location"))
                          {
                              String url = "some URL";
                              request = new JSONRequest();
                              request.setListener(JourneyPlanner.this);
                              request.execute(url);

                              String result = request.get();

                              Object obj = JSONValue.parse(result);
                              JSONArray array = (JSONArray)((JSONObject)obj).get("Locations");

                              for(int i = 0; i < array.size(); i++)
                              {
                                  JSONObject location = (JSONObject) array.get(i);
                                  String desc = (String) location.get("Description");
                                  String id = (String) location.get("Id");

                                  Log.d("filterResults", "Description: " + desc);
                                  Log.d("filterResults", "ID: " + id);

                                  String[] splitted = desc.split(" \\(");
                                  if (splitted.length > 1)
                                      desc = splitted[0];

                                  locationsToID.put(desc, id);
                                  locations.add(desc);
                              }
                          }

                          results.values = locations;
                          results.count = locations.size();

                      }
                      catch (Exception e)
                      {
                          e.printStackTrace();
                      }

                      Log.d("performFiltering", "return FilterResults");
                      return results;
                  }

                  @Override
                  protected void publishResults(CharSequence arg0, FilterResults results) 
                  {  
                      if (results != null && results.count > 0)
                      {
                         notifyDataSetChanged();
                      }
                      else
                      {
                          notifyDataSetInvalidated();
                      }
                  }
            };

            return filter;
        }

I can give you other parts of the code as well if necessary. I have to make a call to the web in order to populate the autocomplete drop down list, I'm guessing that it may be the one causing the exception?


Solution

  • the problem is your "locations" field that you modify in non ui thread (perfornFiltering method), you should use FilterResults which is passed to publishResults