实时搜索:用户完成输入后开始搜索
Realtime Searching: Begin search after user is done typing
在我的应用程序中,当用户在 TextField 中键入内容时,我正在搜索结果。我正在使用提供程序,其中有一个 searchProduct() 函数,每次用户在文本字段中键入内容时都会触发该函数。获取结果后,我将调用 notifyListener() 函数并相应地更新 UI。
我面临的问题是,结果是异步获取的,它们不会同时到达。有时最后一个结果出现在先前结果之一之前。当用户输入太快时,尤其会发生这种情况。因此,每次击键都会调用此 searchProduct() 函数并发出网络请求。这种方法也会发出太多不必要的网络请求,这并不理想。
解决此问题的最佳方法是什么,以便在用户键入搜索字符串的给定时间内,搜索将在用户完成键入后开始?
class ProductService extends ChangeNotifier {
String _searchText;
String serverUrl = 'https://api.example.com/api';
String get searchText => _searchText;
List<Product> products = [];
bool searching = false;
void searchProduct(String text) async {
searching = true;
notifyListeners();
_searchText = text;
var result = await http
.get("$serverUrl/product/search?name=$_searchText");
if (_searchText.isEmpty) {
products = [];
notifyListeners();
} else {
var jsonData = json.decode(result.body);
List<Map<String, dynamic>> productsJson =
List.from(jsonData['result'], growable: true);
if (productsJson.length == 0) {
products = [];
notifyListeners();
} else {
products = productsJson
.map((Map<String, dynamic> p) => Product.fromJson(p))
.toList();
}
searching = false;
notifyListeners();
}
}
}
用户 RestartableTimer 并设置倒计时持续时间,比如 2 秒。用户第一次键入一个字符时,计时器将初始化,然后每次键入一个字符时,它都会重置计时器。如果用户停止输入 2 秒,将触发包含网络请求的回调。显然,代码需要改进以考虑其他情况,例如,如果出于任何原因应在触发之前取消请求。
TextField(
controller: TextEditingController(),
onChanged: _lookupSomething,
);
RestartableTimer timer;
static const timeout = const Duration(seconds: 2);
_lookupSomething(String newQuery) {
// Every time a new query is passed as the user types in characters
// the new query might not be known to the callback in the timer
// because of closures. The callback might consider the first query that was
// passed during initialization.
// To be honest I don't know either if referring to tempQuery this way
// will fix the issue.
String tempQuery = newQuery;
if(timer == null){
timer = RestartableTimer(timeout, (){
myModel.search(tempQuery);
});
}else{
timer.reset();
}
}
在我的应用程序中,当用户在 TextField 中键入内容时,我正在搜索结果。我正在使用提供程序,其中有一个 searchProduct() 函数,每次用户在文本字段中键入内容时都会触发该函数。获取结果后,我将调用 notifyListener() 函数并相应地更新 UI。
我面临的问题是,结果是异步获取的,它们不会同时到达。有时最后一个结果出现在先前结果之一之前。当用户输入太快时,尤其会发生这种情况。因此,每次击键都会调用此 searchProduct() 函数并发出网络请求。这种方法也会发出太多不必要的网络请求,这并不理想。 解决此问题的最佳方法是什么,以便在用户键入搜索字符串的给定时间内,搜索将在用户完成键入后开始?
class ProductService extends ChangeNotifier {
String _searchText;
String serverUrl = 'https://api.example.com/api';
String get searchText => _searchText;
List<Product> products = [];
bool searching = false;
void searchProduct(String text) async {
searching = true;
notifyListeners();
_searchText = text;
var result = await http
.get("$serverUrl/product/search?name=$_searchText");
if (_searchText.isEmpty) {
products = [];
notifyListeners();
} else {
var jsonData = json.decode(result.body);
List<Map<String, dynamic>> productsJson =
List.from(jsonData['result'], growable: true);
if (productsJson.length == 0) {
products = [];
notifyListeners();
} else {
products = productsJson
.map((Map<String, dynamic> p) => Product.fromJson(p))
.toList();
}
searching = false;
notifyListeners();
}
}
}
用户 RestartableTimer 并设置倒计时持续时间,比如 2 秒。用户第一次键入一个字符时,计时器将初始化,然后每次键入一个字符时,它都会重置计时器。如果用户停止输入 2 秒,将触发包含网络请求的回调。显然,代码需要改进以考虑其他情况,例如,如果出于任何原因应在触发之前取消请求。
TextField(
controller: TextEditingController(),
onChanged: _lookupSomething,
);
RestartableTimer timer;
static const timeout = const Duration(seconds: 2);
_lookupSomething(String newQuery) {
// Every time a new query is passed as the user types in characters
// the new query might not be known to the callback in the timer
// because of closures. The callback might consider the first query that was
// passed during initialization.
// To be honest I don't know either if referring to tempQuery this way
// will fix the issue.
String tempQuery = newQuery;
if(timer == null){
timer = RestartableTimer(timeout, (){
myModel.search(tempQuery);
});
}else{
timer.reset();
}
}