Flutter GetX 状态管理不起作用

Posted

技术标签:

【中文标题】Flutter GetX 状态管理不起作用【英文标题】:Flutter GetX state management does not work 【发布时间】:2021-11-10 06:17:34 【问题描述】:

我面临的问题是 ui 文本没有得到更新。我想要的数据,在本例中为 placeName,已在 DEBUG 控制台上成功打印,但它不会更改文本小部件 UI。我认为在 Getx 中的简单语句管理中,它会在方法中使用 update() 更新变量。我遇到过类似的情况,之前我无法弄清楚,所以我不得不使用 statefuleWidget 来解决它。但是,这次我想继续使用 Getx。

enter image description here

有人可以帮帮我吗?

2021-11-10 我更新了我的代码,但它仍然不起作用

2021-11-18 我想出改变函数的返回类型(searchCoordinateAddress)并将其分配给我想要更新的变量(pickUpLocation)。

// home_controller.dart
class HomeController extends GetxController 
  ...
  Rx<Address> pickUpLocation = Address().obs;
  RxBool isLoading = false.obs;
  ...


void locatePosition() async 
  ...
  ...

//  String? address = await UberRepository.to.searchCoordinateAddress(position); // previous

// current
 Address? address = await UberRepository.to.searchCoordinateAddress(position);
 pickUpLocation(address);
 isLoading(true);



// previous
/*
void updatePickUpLocationAddress(Address pickUpAddress) 
print("pickUpAddress.placeName: $pickUpAddress.placeName");
pickUpLocation(pickUpAddress);
print("pickUpLocation.value.placeName: $pickUpLocation.value.placeName");
  

*/
// uber_repository.dart
class UberRepository extends GetConnect 
  static UberRepository get to => Get.find();

  @override
  void onInit() 
    httpClient.baseUrl = 'https://maps.googleapis.com/';
    super.onInit();
  

  // Future<String?> // previous
  // current
  Future<Address?> searchCoordinateAddress(Position position) async 
    String placeAddress = "";

    String url =
        'maps/api/geocode/json?latlng=$position.latitude,$position.longitude&key=$mapKey';

    final response = await get(url);

    if (response.status.hasError) 
      Future.error(response.statusText!);
     else 
      placeAddress = response.body["results"][0]["formatted_address"];

      Address userPickUpAddress = Address();
      userPickUpAddress.latitude = position.latitude;
      userPickUpAddress.longitude = position.longitude;
      userPickUpAddress.placeName = placeAddress;


      return userPickUpAddress; // current

      // HomeController().updatePickUpLocationAddress(userPickUpAddress); // previous


    
    // return placeAddress; // previous
  

// home.dart
class Home extends GetView<HomeController> 
  const Home(
    Key? key,
  ) : super(key: key);

  @override
  Widget build(BuildContext context) 
    return Scaffold(
...
 body:  Stack(
          children: [
            GoogleMap(
              padding: EdgeInsets.only(
                bottom: controller.bottomPaddingOfMap.value,
              ),
              mapType: MapType.normal,
              myLocationButtonEnabled: true,
              initialCameraPosition: controller.kGooglePlex,
              myLocationEnabled: true,
              zoomGesturesEnabled: true,
              zoomControlsEnabled: true,
              onMapCreated: (GoogleMapController googleMapController) 
                controller.controllerGoogleMap.complete(googleMapController);
                controller.newGoogleMapController = googleMapController;
                // when map created and map is set correctly, call current location
                controller.setBottomPaddingOfMap();
                controller.locatePosition(); 
              ,
            ),
...
...
Expanded(
    child: Obx(() => 
                  Column(
              crossAxisAlignment: CrossAxisAlignment.start,
                 children: [
                    // TODO: UI update...
                    !controller.isLoading.value
                          ? CircularProgressIndicator()
                          : Text(
                             controller.pickUpLocation.value != null
                          ? controller.pickUpLocation.value.placeName!
                               : "Add Home",
                               maxLines: 2,
                            overflow: TextOverflow.ellipsis,
                            softWrap: false,
                              ),
                              SizedBox(height: 4.0),
                              Text(
                                "Your living home address",
                                style: TextStyle(
                                  color: Colors.black54,
                                  fontSize: 12.0,
                   ),
                   ),
                  ],
            ),
           ),
     ),
...

// address.dart
class Address 
  String? placeFormattedAddress;
  String? placeName;
  String? placeId;
  double? latitude;
  double? longitude;

  Address(
    this.placeFormattedAddress,
    this.placeName,
    this.placeId,
    this.latitude,
    this.longitude,
  );


【问题讨论】:

【参考方案1】:

您可以使用Obx 来完成。在你的控制器类中做这样的事情

class HomeController extends GetxController 

     Address get pickupLocation => _pickupLocation.value;

  set pickupLocation(Address value) 
    _pickupLocation.value = value;
  

  Rx<Address> pickUpLocation= Rx<Address>(Address());
  ...
  ...
  ...


  void updatePickUpLocationAddress(Address? pickUpAddress) 
    pickUpLocation = pickUpAddress;
    print("Here? $pickUpLocation!.placeName!"); // printed correctly as I intended
  

现在在你的 UI 类中使用 Obx 而不是 GetBuilder 像这样

// home.dart
class Home extends GetView<HomeController> 
  const Home(
    Key? key,
  ) : super(key: key);

  @override
  Widget build(BuildContext context) 
    return Scaffold(
...
...
...
...
            Obx(() => controller.pickupLocation.placeName != null
                        ? Text(controller.pickupLocation.placeName)
                        : Text('Add home')),
...

【讨论】:

我按照你的代码,有空检查错误,我把 Obx(() => ) 移到父Widget,错误消失了,但是placeName数据是'',空字符串.我认为它不适用于ui...我该怎么办? 我可以在 HomeController 上打印我想要的数据,但是 ui 端没有更新并且它显示 ("") 空字符串。所以,我猜 Home 的 build Method,比 HomeController 更早返回 Widget,因此数据不适用于 ui。你对此有什么想法吗? 调用 onInit() 中的 api 方法,并添加一个标志来跟踪您是否已经得到响应。当你加载状态时,你可以显示一个进度对话框,当pickupLocation用api值更新时,更新状态。 我还在为这件事苦苦挣扎...我在Controller上添加了isLoading Rxbool变量,当它为真时我编码,显示placeName,我还检查了打印pickUpLocation.value.placeName是否更新较早比 isLoading 变为真。但是,UI 端的 controller.pickUpLocation.value.placeName 为空。我该怎么办?好郁闷 控制器中的值是否更新?【参考方案2】:

我认为你必须在你的小部件中调用pickUpLocation.refresh()。以下是来自 getx 开发页面 https://pub.dev/packages/get 的示例中的相关部分:

// `Rx` don't have any clue when you change something inside user.
// So, for custom classes, we need to manually "notify" the change.
user.refresh();

【讨论】:

我在 updatePickUpLocationAddress 函数中添加了 pickUpLocation.refresh(),它不起作用,我使用了更新方法,如下所示,```pickUpLocation.update((value) value!.placeName = pickUpAddress.placeName; ); ``` ui 仍然没有更新...我只能看到 placeName 打印正确...但不是在 UI 端。

以上是关于Flutter GetX 状态管理不起作用的主要内容,如果未能解决你的问题,请参考以下文章

使用 GetX 改变主题?

用于 Web 状态管理的 Flutter

使用流在 Flutter 中不起作用检查身份验证状态

PYTHON:简单的浮点转换不起作用,为啥?

Getx HttpClient 不起作用,我已经尝试了互联网上的所有内容

Flutter - Flutter 版本管理 (fvm) 包在 Windows 中不起作用