Flutter优化TextField自动完成实现中的API调用次数

时间:2019-09-01 14:28:28

标签: flutter dart

我正在尝试实现自动完成功能,以便在我的应用中选择地点。为此,我使用Here Maps API。目前,我有一个TextField

onChanged: (query){
    print("Current value is: ${query}");
    if(query) { getPlacesFromHereMaps(query); } 
}, 

这里,每次用户输入字母时,都会在此处调用自动完成API。

因此,如果用户键入“ New York”,则意味着应用程序将调用API约8次,而我发现这太多了。有没有办法对此进行优化?

3 个答案:

答案 0 :(得分:1)

onChanged正在完成其工作。根据文档:

  

每当用户更改时,文本字段就会调用onChanged回调   字段中的文本。如果用户指示输入完毕   在字段中(例如,通过按下软键盘上的按钮),   文本字段调用onSubmitted回调。

如果要优化,可以执行以下操作:

onChanged(query) {
  if (query.length < 2) return;
  // if the length of the word is less than 2, stop executing your API call.

  // rest of your code
  getPlacesFromHereMaps(query);

}

答案 1 :(得分:1)

每当用户结束键入单词或每3(或2)个字符后,您都可以调用API。

但是,当用户提交查询(使用onSubmitted)时,请不要忘记调用API。

解决方案代码:

onChanged: (query){
    print("Current value is: ${query}");
    if((query.length%3==0)||(query[query.length-1]==' ')) { getPlacesFromHereMaps(query); } 

onSubmitted: (query){
   getPlacesFromHereMaps(query);
 }
}, 

=========

替代解决方案:

根据@Karim Elghamry的建议和@CopsOnRoad的关注,您甚至可以使用反跳来改善UX。

在小部件状态下,声明一个控制器和计时器:

final _searchQuery = new TextEditingController();
Timer _debounce;

添加侦听器方法:

_onSearchChanged() {
    if (_debounce?.isActive ?? false) _debounce.cancel();
    _debounce = Timer(const Duration(milliseconds: 500), () {
        getPlacesFromHereMaps(query);
    });
}

将方法挂钩并取消挂钩到控制器:

@override
void initState() {
    super.initState();
    _searchQuery.addListener(_onSearchChanged);
}

@override
void dispose() {
    _searchQuery.removeListener(_onSearchChanged);
    _searchQuery.dispose();
    super.dispose();
}

在构建树中,将控制器绑定到TextField:

child: TextField(
        controller: _searchQuery,
        [...]
    )

来源:How to debounce Textfield onChange in Dart?

答案 2 :(得分:0)

考虑流行的节点包“ debounce”,以下是简单的实现

/// Implementation of well known 'Debounce' node package in Dart
class Debounce {
  final Function _function;
  final Duration _duration;
  Timer _timer;
  int _lastCompletionTime;

  Debounce(this._duration, this._function)
      : assert(_duration != null, "Duration can not be null"),
        assert(function != null, "Function can not be null");

  void schedule() {
    var now = DateTime.now().millisecondsSinceEpoch;

    if (_timer == null || (_timer != null && !_timer.isActive)) {
      _lastCompletionTime = now + _duration.inMilliseconds;
      _timer = Timer(_duration, _function);
    } else {
      _timer?.cancel(); // doesn't throw exception if _timer is not active
      int wait = _lastCompletionTime - now; // this uses last wait time, so we need to wait only for calculated wait time
      _lastCompletionTime = now + wait;
      _timer = Timer(Duration(milliseconds: wait), _function);
    }
  }
}

用法:

1。定义

var debounce = Debounce(Duration(seconds: 1), () {
  getPlacesFromHereMaps(query);
});

2。每次值更改时调用

onChanged: (query){
    print("Current value is: ${query}");
    if(query.trim().length > 3) { d.schedule(); }
}