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 状态管理不起作用的主要内容,如果未能解决你的问题,请参考以下文章