2

Good day, I have the following code and i cannot understand why i get the above error message sporadically. sometimes i get it.. sometimes i don't but i would like to get rid of it.. i have tried everything(some commented out) and some answers here but still having the trouble. can u guys kindly please take a look at it and say where have go wrong because i can't seem to notice it.

 public class SearchAutoCompleteAdapter extends BaseAdapter implements Filterable {

    private ArrayList<BaseAutocompleteItems> resultList;

    private LayoutInflater layoutInflater;
    private Context context;
    private int layout;
    SearchAutoCompleteAPI searchautocomplete = new SearchAutoCompleteAPI();  //does API operation 



    public SearchAutoCompleteAdapter(Context context, int resource) {
        super();
        this.context = context;
        this.layout = resource;
        this.resultList = new ArrayList<BaseAutocompleteItems>();
    }


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


    @Override
    public Object getItem(int index) {
        return resultList.get(index);
    }


    @Override
    public long getItemId(int position) {
        return position;
    }



    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        if (convertView == null) {
            layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = layoutInflater.inflate(layout, null);

        }

        TextView name = (TextView) convertView.findViewById(R.id.suggestion_text_id);
        TextView category = (TextView) convertView.findViewById(R.id.suggestion_category_text_id);

        name.setText(resultList.get(position).getName());
        category.setText(resultList.get(position).getCategoryName());

        return convertView;
    }



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

                FilterResults filterResults = new FilterResults();
                List<BaseAutocompleteItems> tempfilteredProducts;


                //synchronized (filterResults) {

                    if (constraint != null || constraint.length() == 0) {
                        Log.d(SearchogHomeActivity.TAG, "characters in constraints is not null");


                        tempfilteredProducts = searchautocomplete.autocomplete(constraint.toString());

                    } else {

                        tempfilteredProducts = new ArrayList<BaseAutocompleteItems>();
                    }

                    filterResults.values = tempfilteredProducts;
                    filterResults.count = tempfilteredProducts.size();

                    return filterResults;

                //}
            }



            @Override
            protected void publishResults (CharSequence constraint, final FilterResults results){

              //synchronized (results) {
                  resultList = (ArrayList<BaseAutocompleteItems>) results.values;
                  if (results != null && results.count > 0) {

                      notifyDataSetChanged();

                  } else {

                      notifyDataSetInvalidated();
                  }

              }
           // }
        };

        return filter;
    }

}

And this is where i use it in the activity:

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


        textEdit = (AutoCompleteTextView)findViewById(R.id.search_autocomplete_id);
        adapter = new SearchAutoCompleteAdapter(this, R.layout.autocomplete_list);
        textEdit.setText("");
       //textEdit.setThreshold(0);
        textEdit.setOnItemClickListener(this);
        textEdit.setAdapter(adapter);

and here is my log as requested:

 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. Make sure your adapter calls notifyDataSetChanged() when its content changes. [in ListView(-1, class android.widget.ListPopupWindow$DropDownListView) with Adapter(class com.Example.searchAdapter.adapter.SearchAutoCompleteAdapter)]
            at android.widget.ListView.layoutChildren(ListView.java:1562)
            at android.widget.AbsListView.onLayout(AbsListView.java:2148)
            at android.view.View.layout(View.java:15596)
            at android.view.ViewGroup.layout(ViewGroup.java:4966)
            at android.widget.FrameLayout.layoutChildren(FrameLayout.java:573)
            at android.widget.FrameLayout.onLayout(FrameLayout.java:508)
            at android.view.View.layout(View.java:15596)
            at android.view.ViewGroup.layout(ViewGroup.java:4966)
            at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:2072)
            at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1829)
            at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1054)
            at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5779)
            at android.view.Choreographer$CallbackRecord.run(Choreographer.java:767)
            at android.view.Choreographer.doCallbacks(Choreographer.java:580)
            at android.view.Choreographer.doFrame(Choreographer.java:550)
            at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:753)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5221)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

API call:

public  ArrayList<BaseAutocompleteItems> autocomplete(String s){

        //final ArrayList<BaseAutocompleteItems> myresultList = new ArrayList<BaseAutocompleteItems>();
        //myresultList.clear();
        String input = BASE_AUTOCOMPLETE_URL + s;

        Log.d(SearchActivity.TAG, "AutoComplete string is " + input );
        SearchRestClient.get(input, null, new JsonHttpResponseHandler(){

            @Override
            public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
                super.onSuccess(statusCode, headers, response);
            }

            @Override
            public void onSuccess(int statusCode, Header[] headers, JSONArray response) {
                super.onSuccess(statusCode, headers, response);
                ObjectMapper objectmapper = new ObjectMapper();
                objectmapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
                try {
                //1
               //List<BaseAutocompleteItems> autocompleteItems = objectmapper.readValue(String.valueOf(response), objectmapper.getTypeFactory().constructCollectionType(ArrayList.class, BaseAutocompleteItems.class));

                    myresultList = objectmapper.readValue(String.valueOf(response), objectmapper.getTypeFactory().constructCollectionType(ArrayList.class, BaseAutocompleteItems.class));

                      //2
                   /* myresultList.clear();
                    for(BaseAutocompleteItems items: autocompleteItems){
                       myresultList.add(items);
                    }*/
                } catch (IOException e) {
                    e.printStackTrace();
                }


            }

            @Override
            public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) {
                super.onFailure(statusCode, headers, throwable, errorResponse);
            }

            @Override
            public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONArray errorResponse) {
                super.onFailure(statusCode, headers, throwable, errorResponse);
            }
        });

        Log.d(SearchActivity.TAG, "size in adapter is " + myresultList.size());
        return myresultList;

    }
irobotxx
  • 5,963
  • 11
  • 62
  • 91
  • Why do you use the TextWatcher? – user Feb 17 '15 at 20:04
  • @Luksprog sorry for the very late response, i posted this when i was closing from work yesterday. i had used it initially to get character count before the APi was called but then i stopped. i will remove it from the code now but still the same issue. i have included the Log. Thanks – irobotxx Feb 18 '15 at 10:20
  • @Josef sorry for the late response, did not have access to my PC after posting this. I have included my Log file. – irobotxx Feb 18 '15 at 10:22
  • Unless you're doing something fishy in the SearchAutoCompleteAPI class(it's an inner class in the adapter? if yes post its code) your current code shouldn't really throw that exception. – user Feb 18 '15 at 11:24
  • @Luksprog Hi.. i have posted the API call but i think i found the cause of the problem. i was doing the following action with a for-loop(lines commented out with numbers 1 and 2) to populate myresultList instead of just doing it straight. Am guessing that could be the fishy stuff right?. Am testing a lot now to make sure and would let you know. – irobotxx Feb 18 '15 at 12:11
  • That might be it, you could test it by making copies in the performFiltering() method of the list returned by the api call and not just pass it further. – user Feb 18 '15 at 14:52

2 Answers2

1

Here is the getFilter method:which is working fine

@Override
public Filter getFilter() {
    Filter filter = new Filter() {
        @Override
        protected FilterResults performFiltering(final CharSequence constraint) {
            final FilterResults filterResults = new FilterResults();


                    resultList = autocomplete(constraint.toString());

                    // Assign the data to the FilterResults
                    filterResults.values = resultList;
                    filterResults.count = resultList.size();






            return filterResults;
        }

        @Override
        protected void publishResults(CharSequence constraint, final FilterResults results) {
            try {
               activity.runOnUiThread(new Runnable() {
                   @Override
                   public void run() {
                       if (results != null && results.count > 0) {

                          // resultList=(ArrayList<String>)results.values;
                           notifyDataSetChanged();
                       } else {
                           notifyDataSetInvalidated();
                       }
                   }
               });
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    };
    return filter;
}


    public static ArrayList<String> autocomplete(String input) {
    ArrayList<String> resultList = null;


    HttpURLConnection conn = null;
    StringBuilder jsonResults = new StringBuilder();
    try {
        StringBuilder sb = new StringBuilder(Constant.PLACES_API_BASE + Constant.TYPE_AUTOCOMPLETE + Constant.OUT_JSON);
        sb.append("?key=AIzaSyAlU5QFZWbgInmPlV-LWFlXiRS7pZ8wD8o");
        //sb.append("&components=country:au");
        //sb.append("&location=" + String.valueOf(LocationHelperService.dblLatitude) + "," + String.valueOf(LocationHelperService.dblLongitude));
        sb.append("&input=" + URLEncoder.encode(input, "utf8"));
        sb.append("&radius=" + String.valueOf(50));

        URL url = new URL(sb.toString());

        System.out.println("URL: " + url);
        conn = (HttpURLConnection) url.openConnection();
        InputStreamReader in = new InputStreamReader(conn.getInputStream());

        // Load the results into a StringBuilder
        int read;
        char[] buff = new char[1024];
        while ((read = in.read(buff)) != -1) {
            jsonResults.append(buff, 0, read);
        }
    } catch (MalformedURLException e) {
        Log.e(LOG_TAG, "Error processing", e);
        return resultList;
    } catch (IOException e) {
        Log.e(LOG_TAG, "Error connecting to Places API", e);
        return resultList;
    } finally {
        if (conn != null) {
            conn.disconnect();
        }
    }

    try {
        // Create a JSON object hierarchy from the results
        JSONObject jsonObj = new JSONObject(jsonResults.toString());
        JSONArray predsJsonArray = jsonObj.getJSONArray("predictions");

        // Extract the Place descriptions from the results
        resultList = new ArrayList<String>(predsJsonArray.length());
        mainTextList=new ArrayList<String>(predsJsonArray.length());
        secondoryTextList=new ArrayList<String>(predsJsonArray.length());


        for (int i = 0; i < predsJsonArray.length(); i++) {
            System.out.println(predsJsonArray.getJSONObject(i).getString("description"));
            System.out.println("============================================================");
            resultList.add(predsJsonArray.getJSONObject(i).getString("description"));
            mainTextList.add(predsJsonArray.getJSONObject(i).getJSONObject("structured_formatting").getString("main_text"));

            if(predsJsonArray.getJSONObject(i).getJSONObject("structured_formatting").has("secondary_text"))
            {
                secondoryTextList.add(predsJsonArray.getJSONObject(i).getJSONObject("structured_formatting").getString("secondary_text"));
            }
            else{
                secondoryTextList.add("");
            }




        }
    } catch (JSONException e) {
        Log.e(LOG_TAG, "Cannot process JSON results", e);
    }

    return resultList;
}
khushbu
  • 382
  • 1
  • 3
  • 15
  • This is really not a good solution. There's a reason why the performFiltering function is put in a background thread, and it's because it might involve doing extra work you don't want to do in the UI thread. And you're just placing the work back to the UI thread here. – Bilthon Mar 03 '17 at 06:21
  • yes i know it but when i change content in adapter and notify it some times adapter not changes in ui thread because it is in background so for affect on content i need to put filtering result in ui thread. – khushbu Mar 03 '17 at 06:45
  • If you have any another suggestion than let me know i will apply it . – khushbu Mar 03 '17 at 06:45
  • The problem with your code is in this line where you assign the result of the autocomplete method to the resultList variable. If this is the variable used by the adapter, then you're updating it from the background thread and this should not be happening. The right way would be to return the filtered list in the FilterResults and update the resultList variable in the publishResults method. – Bilthon Mar 03 '17 at 18:33
0

I resolved the same issue after a lot of research and debugging. You can take help from here here

Community
  • 1
  • 1
Zafar Imam
  • 319
  • 3
  • 11