2

I have an AutoCompleteTextView that uses a custom layout and retrieves data from my web server. I have it set up so that the app only request data from the server 500 milliseconds after the user has stopped typing into the EditText field.

The only problem is that when I type text into the AutoCompleteTextView, the results show for 500 milliseconds and then disappear (showing only an empty dropdown). I'm not sure what's causing this.

Here is my fragment:

public class MyFragment extends Fragment {

    private AutoCompleteTextView autoCompleteField;

    private Timer timer;

    // 500 millisecond delay before showing the results
    private TextWatcher textWatcher = new TextWatcher() {
        @Override
        public void afterTextChanged(Editable arg0) {
            timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    String autoCompleteText = autoCompleteField.getText().toString();

                    if (!autoCompleteText.isEmpty()) {
                        getResultsFromServer(autoCompleteText);
                    }
                }
            }, 500);
        }

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            //
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count) {
            // Reset the timer
            if (timer != null) {
                timer.cancel();
            }
        }
    };

    public MyFragment() {
        // Required empty public constructor
    }

    public static MyFragment newInstance() {
        MyFragment fragment = new MyFragment();

        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_dog, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        autoCompleteField = (AutoCompleteTextView) view.findViewById(R.id.autoCompleteField);

        autoCompleteField.addTextChangedListener(textWatcher);
    }

    public void getResultsFromServer(String query) {
        ApiInterface apiService = ApiClient.createService(ApiInterface.class);

        Call<List<Dog>> call = apiService.getDogBreeds(query);
        call.enqueue(new Callback<List<Dog>>() {
            @Override
            public void onResponse(Call<List<Dog>> call, Response<List<Dog>> response) {
                List<Dog> dogs = response.body();

                CustomAutoCompleteAdapter adapter = new CustomAutoCompleteAdapter(getContext(), dogs);
                autoCompleteField.setAdapter(adapter);
            }

            @Override
            public void onFailure(Call<List<Dog>> call, Throwable t) {
                //
            }
        });
    }
}

And here is my adapter:

public class CustomAutoCompleteAdapter extends ArrayAdapter<Dog>
{
    private List<Dog> dogs;
    private List<Dog> filteredDogs = new ArrayList<>();

    public CustomAutoCompleteAdapter(Context context, List<Dog> dogs) {
        super(context, 0, dogs);
        this.dogs = dogs;
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Dog dog = filteredDogs.get(position);

        LayoutInflater inflater = LayoutInflater.from(getContext());
        convertView = inflater.inflate(R.layout.custom_autocomplete_layout, parent, false);

        ImageView image = (ImageView) convertView.findViewById(R.id.image);
        TextView text = (TextView) convertView.findViewById(R.id.text);

        // Set the breed's image
        Glide.with(context)
            .load("http://www.website.com/dogs/" + dog.getId() + ".png")
            .into(image);

        // Set the breed name
        text.setText(dog.getBreedName());

        return convertView;
    }

    @Override
    public Filter getFilter() {
        return new DogsFilter(this, dogs);
    }

    class DogsFilter extends Filter {
        CustomAutoCompleteAdapter adapter;
        List<Dog> originalList;
        List<Dog> filteredList;

        public DogsFilter(CustomAutoCompleteAdapter adapter, List<Dog> originalList) {
            super();
            this.adapter = adapter;
            this.originalList = originalList;
            this.filteredList = new ArrayList<>();
        }

        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            filteredList.clear();
            final FilterResults results = new FilterResults();

            if (constraint == null || constraint.length() == 0) {
                filteredList.addAll(originalList);
            } else {
                final String filterPattern = constraint.toString().toLowerCase().trim();

                // Your filtering logic goes in here
                for (final Dog dog : originalList) {
                    if (dog.getBreedName().toLowerCase().contains(filterPattern)) {
                        filteredList.add(dog);
                    }
                }
            }

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

            return results;
        }

        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            adapter.filteredDogs.clear();
            adapter.filteredDogs.addAll((List) results.values);
            adapter.notifyDataSetChanged();
        }
    }
}

What could be causing the results to show for 500 milliseconds (which happens to equal the AutoCompleteTextView delay) and then disappear?

1 Answers1

2

It is because your are using a Timer to schedule the task in every 500 ms. in your afterTextChanged() method.

Modify your implementation to:

    CustomAutoCompleteAdapter adapter;  //declare globally

@Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        autoCompleteField = (AutoCompleteTextView) view.findViewById(R.id.autoCompleteField);

        String autoCompleteText = autoCompleteField.getText().toString();
        if (!autoCompleteText.isEmpty()) {
            getResultsFromServer(autoCompleteText);
        }
        autoCompleteField.addTextChangedListener(textWatcher);
    }



private TextWatcher textWatcher = new TextWatcher() {

    long lastPress = 0l;
    @Override
    public void afterTextChanged(Editable arg0) {
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {
        //
    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        if (System.currentTimeMillis() - lastPress > 1000) {
                lastPress = System.currentTimeMillis();
                adapter.getFilter().filter(s.toString());   //filter adpater data
            }
    }
};
rafsanahmad007
  • 23,683
  • 6
  • 47
  • 62
  • This seems to have caused a different, but similar problem. Now, the first time I type into the field (like "Hel"), it shows the suggestions fine, but if I continue typing the word (like "Hello"), the suggestion disappears again. – user7704171 Mar 13 '17 at 16:47