Flutter GetX控制器初始化报错:无法通过Get.find()获取PopularProductController
问题描述
在Flutter项目对接JSON API时,使用GetX依赖注入初始化PopularProductController后,在main.dart中调用Get.find<PopularProductController>().getPopularProductList()时出现找不到控制器的错误,提示需要调用Get.put或Get.lazyPut。
相关代码文件
depencies.dart
import 'package:food_delivery/controllers/popular_product_controller.dart'; import 'package:food_delivery/data/api/apiclient.dart'; import 'package:food_delivery/data/repository/popular_product_repo.dart'; import 'package:get/get.dart'; Future<void> init() async { //api clinet Get.lazyPut(() => ApiClient(appBaseUrl: 'https://mvs.bslmeiyu.com')); //repository Get.lazyPut(() => PopularProductRepo(apiClient: Get.find())); //controllers Get.lazyPut(() => PopularProductController(popularProductRepo: Get.find())); }
popular_product_repo.dart
import 'package:food_delivery/data/api/apiclient.dart'; import 'package:get/get.dart'; class PopularProductRepo extends GetxService { final ApiClient apiClient; PopularProductRepo({required this.apiClient}); Future<Response> getPopularProductList() async { return await apiClient .getData('http://mvs.bslmeiyu.com/api/v1/products/popular'); } }
popular_product_controller.dart
import 'package:food_delivery/data/repository/popular_product_repo.dart'; import 'package:food_delivery/models/products_model.dart'; import 'package:get/get.dart'; class PopularProductController extends GetxController { final PopularProductRepo popularProductRepo; PopularProductController({required this.popularProductRepo}); List<dynamic> _popularProductList = []; List<dynamic> get popularProductList => _popularProductList; Future<void> getPopularProductList() async { Response response = await popularProductRepo.getPopularProductList(); if (response.statusCode == 200) { _popularProductList = []; _popularProductList.addAll(Product.fromJson(response.body).products); update(); } else { return null; } } }
product_model.dart
class Product { int? _totalSize; int? _typeId; int? _offset; late List<ProductModel> _products; List<ProductModel> get products => _products; Product( {required totalSize, required typeId, required offset, required products}) { this._totalSize = totalSize; this._typeId = typeId; this._offset = offset; this._products = products; } Product.fromJson(Map<String, dynamic> json) { _totalSize = json['total_size']; _typeId = json['type_id']; _offset = json['offset']; if (json['products'] != null) { _products = <ProductModel>[]; json['products'].forEach((v) { _products!.add(ProductModel.fromJson(v)); }); } } } class ProductModel { int? id; String? name; String? description; int? price; int? stars; String? img; String? location; String? createdAt; String? updatedAt; int? typeId; ProductModel( {this.id, this.name, this.description, this.price, this.stars, this.img, this.location, this.createdAt, this.updatedAt, this.typeId}); ProductModel.fromJson(Map<String, dynamic> json) { id = json['id']; name = json['name']; description = json['description']; price = json['price']; stars = json['stars']; img = json['img']; location = json['location']; createdAt = json['created_at']; updatedAt = json['updated_at']; typeId = json['type_id']; } }
apiclient.dart
import 'package:get/get.dart'; class ApiClient extends GetConnect implements GetxService { late String token; final String appBaseUrl; late Map<String, String> _mainHeaders; ApiClient({required this.appBaseUrl}) { baseUrl = appBaseUrl; timeout = Duration(seconds: 30); _mainHeaders = { 'Content-type': 'application/json; charset=UTF-8', 'Authorization': 'Bearer $token', }; } Future<Response> getData(String uri) async { try { Response response = await get(uri); return response; } catch (e) { return Response(statusCode: 1, statusText: e.toString()); } } }
main.dart
import 'package:flutter/material.dart'; import 'package:food_delivery/controllers/popular_product_controller.dart'; import 'package:food_delivery/pages/food/popular_food_detail.dart'; import 'package:food_delivery/pages/food/recomended_food_detail.dart'; import 'package:food_delivery/pages/home/main_food_page.dart'; import 'package:food_delivery/data/repository/popular_product_repo.dart'; import 'package:get/get.dart'; import 'helper/depencies.dart' as dep; Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await dep.init; // Initialize the PopularProductController runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { Get.find<PopularProductController>().getPopularProductList(); return GetMaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: RecomencedFoodDetail(), ); } }
错误信息
════════ Exception caught by widgets library ═══════════════════════════════════
The following message was thrown building MyApp(dirty):
"PopularProductController" not found. You need to call "Get.put(PopularProductController())" or "Get.lazyPut(()=>PopularProductController())"
解决方案
1. 理解Get.lazyPut的延迟特性
Get.lazyPut是延迟初始化,只有当第一次调用Get.find()时才会创建实例。但你在MyApp的build方法中直接调用Get.find(),此时GetMaterialApp还未完成初始化,GetX的依赖容器还未准备好,导致找不到控制器实例。
2. 调整接口调用时机
方式一:在页面的initState中调用
将接口调用移到首页的initState生命周期中,确保GetMaterialApp已经初始化:
class MainFoodPage extends StatefulWidget { const MainFoodPage({Key? key}) : super(key: key); @override State<MainFoodPage> createState() => _MainFoodPageState(); } class _MainFoodPageState extends State<MainFoodPage> { @override void initState() { super.initState(); // 此时GetMaterialApp已初始化,可正常获取控制器 Get.find<PopularProductController>().getPopularProductList(); } @override Widget build(BuildContext context) { return Scaffold( // 页面内容 ); } }
同时修改main.dart的home为MainFoodPage():
return GetMaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MainFoodPage(), );
方式二:利用控制器的onInit生命周期
在PopularProductController中重写onInit方法,自动触发接口调用,控制器实例化时会自动执行:
class PopularProductController extends GetxController { final PopularProductRepo popularProductRepo; PopularProductController({required this.popularProductRepo}); List<dynamic> _popularProductList = []; List<dynamic> get popularProductList => _popularProductList; @override void onInit() { // 控制器初始化时自动调用接口 getPopularProductList(); super.onInit(); } Future<void> getPopularProductList() async { Response response = await popularProductRepo.getPopularProductList(); if (response.statusCode == 200) { _popularProductList = []; _popularProductList.addAll(Product.fromJson(response.body).products); update(); } else { // 替换return null,用提示反馈错误 Get.snackbar("请求失败", "无法获取热门商品数据"); } } }
3. 修复API URL不一致问题
PopularProductRepo中使用了完整HTTP URL,但ApiClient的baseUrl是HTTPS,协议不一致会导致请求失败,改为仅传路径:
Future<Response> getPopularProductList() async { return await apiClient.getData('/api/v1/products/popular'); }
4. 修复ApiClient的token未初始化问题
ApiClient中的token是late变量,初始化时未赋值会导致空指针,添加默认值:
ApiClient({required this.appBaseUrl}) { baseUrl = appBaseUrl; timeout = Duration(seconds: 30); token = ""; // 先设空,后续可通过方法更新 _mainHeaders = { 'Content-type': 'application/json; charset=UTF-8', 'Authorization': 'Bearer $token', }; }
内容的提问来源于stack exchange,提问作者LukaszAdler

