城市和地图位置从哪里来
地址选择页初始化时优先使用当前地区;没有地区信息时再用通用默认位置。地图创建后保存地图控制器,用户切换地区时移动镜头并重新获取附近地点。
附近列表和关键词搜索分别通过对应的数据接口加载。空关键词时,控制器则把附近地址映射成统一的搜索结果模型,避免页面同时维护两套展示结构。
用路由结果把地址交回去
用户点选列表项后,控制器记录一次地址选择行为,再调用 Get.back(result: address)。发起选择的页面 await Get.toNamed(…) 后读取返回值,写入表单状态并按需重新计算总额。
这个模式适合短暂的“选择器”页面:页面只负责找到并返回值,调用方负责决定如何更新业务状态。返回模型时最好统一类型,减少 dynamic 在多处传播。
当前搜索是逐字请求
地图搜索输入框的 onChanged 直接调用 搜索结果加载方法。输入“咖啡店”时,用户每输入一个字符都会尝试请求一次;而控制器当前没有防抖、取消旧请求或比较查询版本。慢响应如果后到,也可能覆盖较新的关键词结果。
可改进的方向是:输入后等待短暂间隔,只提交最后一个查询;每次请求捕获当时的关键词和城市;响应返回时确认请求编号仍是最新。空关键词时则直接显示已经加载的附近结果。
Timer? _debounce;
int _queryVersion = 0;
void onQueryChanged(String value) {
_debounce?.cancel();
final version = ++_queryVersion;
_debounce = Timer(const Duration(milliseconds: 350), () async {
final query = value.trim();
if (query.isEmpty) {
results.value = nearbyResults;
return;
}
final matches = await repository.search(query);
if (version == _queryVersion) {
results.value = matches;
}
});
}
void disposeSearch() {
_debounce?.cancel();
_queryVersion++;
}
控制器资源要有对应的释放点
控制器创建了 TextEditingController、FocusNode 和 RefreshController,但目前没有启用的 onClose() 来释放它们。页面退出后这些资源可能继续保留监听或等待刷新。处理时应实现释放,并覆盖连续打开、关闭页面和请求尚未完成时离开的场景。
另一个小边界是 附近结果加载方法 使用异步方法但没有 try/catch;网络错误时调用方没有明确的失败状态。为附近列表增加加载、空态和错误态,会比仅显示空白更容易解释问题。
经验总结
防抖这段 Timer+_queryVersion 的写法,我摘出来用 dart 跑过:快速输入只提交最后一次、慢到的旧请求被丢弃、空关键词回退附近结果,断言全过,可以直接抄。但示例应用里有个真实缺口:控制器建了 TextEditingController、FocusNode 和 RefreshController,却没有 onClose() 释放。页面反复进出后内存慢慢涨,九成是没释放的 controller 在作祟。修法很机械:建了什么就在 onClose 里释放什么,顺手把 _debounce?.cancel() 也写进去,别靠记忆。另外附近结果加载方法用了 async 却没有 try/catch,网络一抖页面就是空白——给附近列表补上加载、空态、错误态三个状态,比”一片空白”好排查十倍,用户也知道发生了什么。
小结
地图位置选择的核心在于让城市、地图镜头、附近地点、关键词结果和下单地址共享一致的数据。路由回传方式可以保持简单;搜索节流、旧响应处理和控制器释放是可以继续打磨的地方。
