Autocompletion delay

前端 未结 4 488
予麋鹿
予麋鹿 2020-12-17 06:33

I\'ve got to set an autocompletion for my application.

I\'ve already understood the AutoCompleteTextView operation, but I\'d like to dynamically modify the Stri

相关标签:
4条回答
  • 2020-12-17 07:04

    It can be easily done using handler. Just need to remove all runnable before API calls. Below code is for same

    /**
    * Created by Shahbaz Hashmi on 12/01/19.
    */
    public class AutoCompleteAdapter extends ArrayAdapter<Place> implements Filterable {
    
    private static final String TAG = AutoCompleteAdapter.class.getSimpleName();
    
    private static final int DELAY = 800; // 0.8 seconds delay
    
    private Handler handler;
    
    private Runnable runnable;
    
    private ArrayList<Place> data;
    private Context context;
    private Location location;
    private CompositeDisposable mCompositeDisposable;
    
    public AutoCompleteAdapter(Context context, int resource, Location location) {
        super(context, resource);
        this.context = context;
        this.data = new ArrayList<>();
        this.location = location;
        handler = new Handler();
        mCompositeDisposable = new CompositeDisposable();
    }
    
    @Override
    public int getCount() {
        return data.size();
    }
    
    @Nullable
    @Override
    public Place getItem(int position) {
        return data.get(position);
    }
    
    @NonNull
    @Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            protected FilterResults performFiltering(final CharSequence constraint) {
                final FilterResults results = new FilterResults();
                if (constraint != null) {
    
                    handler.removeCallbacksAndMessages(null);
    
                    mCompositeDisposable.clear();
    
                    handler.postDelayed(runnable , DELAY);
    
                    runnable = new Runnable() {
                        @Override
                        public void run() {
                            ///
    
                            mCompositeDisposable.add(NetworkClient.getRetrofit().create(NetworkInterface.class)
                                    .getPredictions(MapHelper.makeAutocompleteURL((BaseActivity) context, location, constraint.toString(), Config.SEARCH_RADIUS * 1000))
                                    .subscribeOn(Schedulers.io())
                                    .observeOn(AndroidSchedulers.mainThread()).subscribeWith(new DisposableObserver<PlaceSerializer>(){
                                        @Override
                                        public void onNext(PlaceSerializer placeSerializer) {
                                            LogHelper.d(TAG, "got data form prediction API");
                                            data = new ArrayList<Place>(placeSerializer.getPlaces());
                                            results.values = data;
                                            results.count = data.size();
                                            notifyDataSetChanged();
                                        }
    
                                        @Override
                                        public void onError(Throwable e) {
                                            LogHelper.e(TAG, e.getMessage());
                                        }
    
                                        @Override
                                        public void onComplete() {
    
                                        }
                                    }));
    
                            results.values = data;
                            results.count = data.size();
    
                            ///
                        }
                    };
    
                }else{
                    if(data.size()>0) data.clear();
                }
                return results;
            }
    
            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                if (results != null && results.count > 0) {
                    notifyDataSetChanged();
                } else notifyDataSetInvalidated();
            }
        };
    }
    
    
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Place place = getItem(position);
        if (convertView == null) {
            convertView = LayoutInflater.from(getContext()).inflate(R.layout.row_autocomplete, parent, false);
        }
    
        TextView primaryText = (TextView) convertView.findViewById(R.id.primary_text);
        TextView secondaryText = (TextView) convertView.findViewById(R.id.secondary_text);
    
        primaryText.setText(place.getStructuredFormatting().getMainText());
        secondaryText.setText(place.getStructuredFormatting().getSecondaryText());
    
        return convertView;
      }
    }
    
    0 讨论(0)
  • 2020-12-17 07:06

    I'd keep a long named lastPress as a field on my TextWatcher. When you press a key, set lastPress = System.currentTimeMillis(). Then just wrap your entire onTextChanged in a if with condition if(System.currentTimeMillis() - lastPress>500) and set lastPress again in that if.


    new TextWatcher(){
        long lastPress = 0l;
        @Override
        public void onTextChanged(CharSequence s,
                 int start, int before, int count){
            if(System.currentTimeMillis() - lastpress > 500){
                lastPress= System.currentTimeMillis();
                GetAutocompletion ac = new GetAutocompletion();
                ac.execute(zipBox.getText().toString());
            }
        }
        // Other methods to implement
    }
    
    0 讨论(0)
  • 2020-12-17 07:25

    Can't comment on the answer selected as correct so here it goes. This solution will only work if you press a key after the specified delay has elapsed. If you write very fast and then stop no request will be sent to the server.

    You can make that happen using a Handler and sending messages delayed:

    public void onTextChanged(CharSequence s, int start, int before,
                               int count) {
    
        final String term = s.toString();
        if( term.length() > 3 ){
            autocompleteHandler.removeMessages(0);
            autocompleteHandler.postDelayed(new Runnable(){
                @Override
                public void run() {
                new SearchLocationAsyncTask(context, term).execute();
            }}, 350);
        }
    }
    

    Where SearchLocationAsynTask calls your server and updates the view accordingly.

    Basically what this does is add a new message to the handler everytime the text changes, if there are any messages in the queue they get deleted and a new one is added to execute in 350ms.

    0 讨论(0)
  • 2020-12-17 07:27

    I have got the same problem. The data comes but the autocompleteTextView doesn't update. The reason why the data is not updated is because the adapter didn't inform that the dataset has been changed.

     //use this at the initialization part for the autocompleteTextView
     autocompleteTextView.setThreshold(1);
     myAdapter.setNotifyOnChange(true);
     autocompleteTextView.setAdapter(myAdapter);
    
     // use this when you get new dataset and will show on autocompleteTextView
     myAdapter.notifyDataSetChanged();
    
    0 讨论(0)
提交回复
热议问题