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

如何创建带工厂方法的单例LocationService类并传递构造参数?

带构造参数的单例LocationService实现及必要性分析

问题原因

你尝试的单例实现报错The instance member 'context' can't be accessed in an initializer,是因为静态成员_instance初始化时,直接引用了类的实例成员(如context、update_drivers等)。静态成员的初始化阶段早于实例创建,此时实例成员还未存在,因此会触发错误。

正确的单例实现方案

通过延迟初始化静态实例,在工厂方法中接收构造参数,确保实例仅被创建一次:

class LocationService {
  late Position position;
  GeoPoint? initPosition;
  bool loadGeoFire = false;
  final Function update_drivers;
  final bool nearbyAvailableDriverKeysLoaded;
  final bool removeDriverIcon;
  final String? removeDriverKey;
  final GeoPoint? initialInitPosition;
  final bool initialLoadGeoFire;

  // 静态可空实例,延迟初始化
  static LocationService? _instance;

  // 工厂方法:接收参数,仅在实例未创建时初始化
  factory LocationService({
    required Function update_drivers,
    required bool nearbyAvailableDriverKeysLoaded,
    required bool removeDriverIcon,
    required String? removeDriverKey,
    required GeoPoint? initPosition,
    required bool loadGeoFire,
  }) {
    _instance ??= LocationService._internal(
      update_drivers: update_drivers,
      nearbyAvailableDriverKeysLoaded: nearbyAvailableDriverKeysLoaded,
      removeDriverIcon: removeDriverIcon,
      removeDriverKey: removeDriverKey,
      initialInitPosition: initPosition,
      initialLoadGeoFire: loadGeoFire,
    );
    return _instance!;
  }

  // 私有构造函数
  LocationService._internal({
    required this.update_drivers,
    required this.nearbyAvailableDriverKeysLoaded,
    required this.removeDriverIcon,
    required this.removeDriverKey,
    required this.initialInitPosition,
    required this.initialLoadGeoFire,
  }) {
    initPosition = initialInitPosition;
    loadGeoFire = initialLoadGeoFire;
  }

  // 修改locatePosition:将context改为方法参数,避免持有上下文导致内存泄漏
  Future<void> locatePosition(BuildContext context) async {
    final appData = context.read<AppData>();
    position = await Geolocator.getCurrentPosition(
        desiredAccuracy: LocationAccuracy.high);
    print("This is your Position:: " + position.toString());

    GeoPoint initPos =
        GeoPoint(latitude: position.latitude, longitude: position.longitude);

    initPosition = initPos;
    appData.initPosition = initPos;

    String address =
        await AssistantMethods.searchCoordinateAddress(position, context);
    print("This is your Address:: " + address);

    if (!loadGeoFire) {
      initializeGeoFire(
        position: position,
        update_drivers: update_drivers,
        nearbyAvailableDriverKeysLoaded: nearbyAvailableDriverKeysLoaded,
        removeDriverIcon: removeDriverIcon,
        removeDriverKey: removeDriverKey,
      );
      loadGeoFire = true;
    }

    Provider.of<AppData>(context, listen: false).closeSplashScreen(false, true);
    AssistantMethods.retrieveHistoryInfo(context);
  }
}

调用方式

首次调用传递参数创建实例,后续调用直接复用已有实例:

@override
Future<void> mapIsReady(bool isReady) async {
  LocationService locationService = LocationService(
    update_drivers: update_drivers,
    nearbyAvailableDriverKeysLoaded: nearbyAvailableDriverKeysLoaded,
    removeDriverIcon: removeDriverIcon,
    removeDriverKey: removeDriverKey,
    initPosition: initPosition,
    loadGeoFire: loadGeoFire,
  );

  // 调用时传入context
  await locationService.locatePosition(context);
}

单例必要性判断

是否需要单例,取决于你的业务需求:

  • 需要单例的场景:如果多处调用locatePosition时,需要共享状态(比如loadGeoFire仅需初始化一次、position等数据需要在不同调用中保持一致),单例是合适的,能避免重复初始化和状态不一致问题。
  • 不需要单例的场景:如果每次调用locatePosition都需要独立执行(比如每次都要重新获取位置、重新初始化GeoFire),直接实例化新的LocationService即可,无需单例。

内容的提问来源于stack exchange,提问作者Pannam T

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 23:03:07