You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用Future函数后值仍为Null?Flutter地理定位数据处理问题

异步获取地理距离并排序列表的问题

我用geolocator插件获取地理定位数据,想把拿到的距离值存入列表用来排序,但添加数据时出现了值为Null的错误,还有调用add()方法时的Null接收器错误。我知道这是Future变量和普通变量处理方式不一样导致的,想请教怎么把Future变量转换成普通变量?相关代码和错误如下:


主代码(创建Widget列表,需按距离排序)

return ListView( 
  // 此部分正常工作,用于获取Firebase文档
  children: snapshot.data.docs.map((document) { 
    GeoPoint tempVar = document['location'];
    // 此部分无法正常工作
    List<int> widgetIds;
    Future<double> listValue = getDistance(tempVar);
    listValue.then((double future) {
      if(listValue != null){
        var newV = myList(listValue.round());
        print('$newV');
      }
      if(listValue == null){}
    });
    // 此部分正常工作,用于生成自定义Widget
    return canTemplate(document, context,);
  }).toList(), 
); 

getDistance()函数

Future <double> getDistance(GeoPoint loc) async {
  Position position = await Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.high); 
  double lat1 = position.latitude;
  double long1 = position.longitude;
  double lat2 = loc.latitude;
  double long2 = loc.longitude;
  double distanceInMeters = await Geolocator().distanceBetween(lat1, long1, lat2, long2);
  double feet = distanceInMeters * 3.28084;
  return feet;
}

myList函数

Future <List> myList(int data) async{
  List widgetIds;
  widgetIds.add(data);
  return widgetIds;
}

遇到的错误

/flutter ( 5177): Closure: (int) => Future<List> from Function 'myList': static.
E/flutter ( 5177): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: NoSuchMethodError: The method 'add' was called on null.
E/flutter ( 5177): Receiver: null
E/flutter ( 5177): Tried calling: add(1046046)

可以看到目标数值能获取到,但还是被判定为Null。另外尝试用await调用时,把var newV = myList(listValue.round());改成var newV = await myList(listValue.round());,系统提示“await只能用于Future,不能用于double”。


解决方法

1. 先修复myList的空指针问题

myList里的widgetIds没有初始化,直接调用add()肯定报错,改成:

// 没必要做成Future,同步函数即可
List<int> myList(int data) {
  List<int> widgetIds = []; // 初始化空列表
  widgetIds.add(data);
  return widgetIds;
}

2. 正确获取Future的实际值

在then回调里,你错误地用了listValue.round(),但listValue是Future对象,不是实际的double值,应该用回调参数里的真实值:

listValue.then((double actualValue) {
  if(actualValue != null){
    var newV = myList(actualValue.round());
    print('$newV');
  }
});

3. 实现按距离排序的正确思路

你当前的写法是在遍历文档时异步获取距离,没法直接排序(因为ListView已经提前生成)。正确流程应该是:

  • 先批量获取所有Firebase文档
  • 一次性计算所有文档的距离,把文档和距离绑定成对象
  • 按距离排序后再生成ListView

示例代码:

// 定义类存储文档和对应距离
class DocumentWithDistance {
  final DocumentSnapshot doc;
  final double distance;

  DocumentWithDistance(this.doc, this.distance);
}

// 封装排序逻辑的异步方法
Future<List<DocumentWithDistance>> _getSortedDocuments() async {
  // 获取当前用户位置
  Position position = await Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.high); 
  double userLat = position.latitude;
  double userLng = position.longitude;

  // 获取Firebase所有文档
  QuerySnapshot snapshot = await FirebaseFirestore.instance.collection('你的集合名').get();
  
  // 遍历文档计算距离,存入列表
  List<DocumentWithDistance> docList = [];
  for(var doc in snapshot.docs) {
    GeoPoint loc = doc['location'];
    double distanceInMeters = Geolocator.distanceBetween(userLat, userLng, loc.latitude, loc.longitude);
    double feet = distanceInMeters * 3.28084;
    docList.add(DocumentWithDistance(doc, feet));
  }

  // 按距离从小到大排序
  docList.sort((a, b) => a.distance.compareTo(b.distance));
  
  return docList;
}

// 用FutureBuilder构建排序后的ListView
@override
Widget build(BuildContext context) {
  return FutureBuilder<List<DocumentWithDistance>>(
    future: _getSortedDocuments(),
    builder: (context, snapshot) {
      if(snapshot.connectionState == ConnectionState.waiting) {
        return Center(child: CircularProgressIndicator());
      }
      if(snapshot.hasError) {
        return Center(child: Text('加载出错'));
      }
      return ListView(
        children: snapshot.data.map((item) {
          return canTemplate(item.doc, context);
        }).toList(),
      );
    },
  );
}

4. 关于await错误的解释

你之前用await myList(listValue.round())报错,是因为listValue是Future,直接调用round()是在Future对象上调用方法,不是真实的double值。正确写法需要先await获取实际值:

// 必须在async函数内使用
double actualValue = await listValue;
var newV = myList(actualValue.round());

内容的提问来源于stack exchange,提问作者Grace Thomas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 11:02:08