首页 > 解决方案 > Flutter:在关闭控制器上处理 HTTP 请求

问题描述

原始答案

我在 Flutter 上使用 Getx 状态管理。

尽可能简化:

我构建了一个 GetxController 来控制我的页面,并且在这个控制器中我有一个 StatefulWidget 实例,它可以唤起 http 请求。

class MyController extends GetxController {
  Player player;
}   

class Player extends StatefulWidget {
  PlayerState state;

  @override
  PlayerState createState() {
    state = PlayerState();
    return state;
  }
}

class PlayerState extends State<Player> {
  void methodName async() {
    futureRequest().then((data) {
      // when the error ocurrs
      setState(() {});
    });
  }
}

当用户在请求结束之前关闭移动页面,触发控制器的 close 方法时,就会出现问题。

这样,当 setState 被触发时,没有更多的页面实例,就会发生错误。

我相信解决方案是在调用控制器关闭方法时中断与此 GetxController 相关的所有请求并“删除”此 StatefulWidget 实例。

我不知道这是否正确,如果它是如何做到的..

==================================================== =================

更新的答案

主要问题是 getDetails() 方法中的异步请求,即使在控制器被释放后,即使使用 GetBuilder 也会返回响应,并且该响应带有来自 videoPlayerController(video_player 插件实例)启动的视频的 url。

因此,用户在另一个屏幕上,但继续收听在后台播放的视频。

作为一种解决方法并考虑将良好实践应用于代码,我按照 GetX 规则进行了重构以仅使用无状态小部件。我解决了这个问题,但我必须将Future转换为Stream

正在使用 Get.lazyPut() 创建绑定以执行依赖项注入:

class Binding implements Bindings {
  Get.lazyPut<PlayerController>(() {
    return PlayerController(videoRepository: VideoRepository(VideoProvider(Dio())));
  });
}

此绑定链接到基于 GetX 文档的页面路由器。

class AppPages {
  static final routes = [
    GetPage(name: Routes.MyRoute, page: () => MyPage(), binding: MyBinding()),
  ];
}

为了防止控制器在处置之前采取行动,我必须创建一个 Stream 并在控制器处置时取消它。

class MyController extends GetxController {
  
  MyController({@required this.repository}) : assert(repository != null);
  StreamSubscription<bool> stream;
  // Instance of plugin video_player 
  VideoPlayerController videoPlayerController;

  @override
  void onClose() {
    if (streamGetVideo != null) streamGetVideo.cancel();
    super.onClose();
    if (videoPlayerController != null) videoPlayerController?.dispose();
  }

  // This is the method called by the user on screen
  void loadVideo() {
    stream = getDetails().asStream().listen((bool response) {
      // This code is canceled on onClose() method by the stream
      if (response) update();
    });
  }

  Future<bool> getDetails() async {
    return await repository.getDetails().then((data) async {
      videoPlayerController = VideoPlayerController.network(data);
      initFuture = videoPlayerController.initialize();
      await initFuture.whenComplete(() { return true; });
    });
  }
}

我认为 Flutter/GetX 应该有更好的方法来做到这一点,没有我做的这些变通方法。如果有人有更好的方法或提示,我愿意接受建议。

标签: flutterasynchronousflutter-getx

解决方案


一种解决方案可能是将您的 setState 与

    if(mounted){
          setState(() {});
    }

推荐阅读