如何创建带工厂方法的单例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
相关产品推荐
相关产品推荐

