当前位置: 首页 > 知识库问答 >
问题:

flutter - 如何让SongDetailsBottomsheetController释放并在每次打开BottomSheet时重新初始化?

微生德泽
2024-08-02

如何让SongDetailsBottomsheetController释放并在每次打开BottomSheet时重新初始化

class SongDetailsBottomsheet extends StatelessWidget {
  final SongDetailsBottomsheetController controller;
  SongDetailsBottomsheet({super.key, required MediaItem track})
      : controller = Get.put(SongDetailsBottomsheetController(track: track));

  @override
  Widget build(BuildContext context) {
    return const SizedBox(
            height: 220,
            child: Column(
              children: [
                SizedBox(width: 100,height: 100,)
              ],
            ),
          );
  }
}
class SongDetailsBottomsheetController extends GetxController {
  // bool isLoading = true;
  // late String avatarUrl;
  final MediaItem track;
  SongDetailsBottomsheetController({required this.track});

  @override
  void onInit() {
    super.onInit();
    debugPrint('start');
  }

  @override
  void onReady() {
    super.onReady();
    debugPrint('ready');
    // getArtistAvatar();
  }
  @override
  onClose(){
    super.onClose();
    debugPrint('closing');

  }
       onPressed: () {
            showModalBottomSheet(
                context: context,
                builder: (context) {
                  return SongDetailsBottomsheet(track: track);
                });
}

当按下按钮时,弹出BottomSheet,但关闭时不会打印"closing",当再次打开时,也不会重新调用OnInit()和OnReady(),每次传入的MediaItem都不同,但SongDetailsBottomsheetController中的MediaItem不变

调试信息:
I/flutter (25437): start
I/flutter (25437): ready
W/WindowOnBackDispatcher(25437): OnBackInvokedCallback is not enabled for the application.
W/WindowOnBackDispatcher(25437): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
D/SystemUtils(25437): [isSystemApp] begin android.app.Application@da53904
D/ScreenUtils(25437): isMultiWindow:0,userId:0
D/ScreenUtils(25437): hasVivoFreeformTasks:0,userId:0
D/ScreenUtils(25437): isLittleVExist:0,userId:0
D/SystemUtils(25437): userId:0
D/SystemUtils(25437): [isSystemApp] begin android.app.Application@da53904
D/ScreenUtils(25437): isMultiWindow:0,userId:0
D/ScreenUtils(25437): hasVivoFreeformTasks:0,userId:0
D/ScreenUtils(25437): isLittleVExist:0,userId:0
D/SystemUtils(25437): userId:0
D/SystemUtils(25437): [isSystemApp] begin android.app.Application@da53904
D/ScreenUtils(25437): isMultiWindow:0,userId:0
D/ScreenUtils(25437): hasVivoFreeformTasks:0,userId:0
D/ScreenUtils(25437): isLittleVExist:0,userId:0
D/SystemUtils(25437): userId:0
D/SystemUtils(25437): [isSystemApp] begin android.app.Application@da53904
D/ScreenUtils(25437): isMultiWindow:0,userId:0
D/ScreenUtils(25437): hasVivoFreeformTasks:0,userId:0
D/ScreenUtils(25437): isLittleVExist:0,userId:0
D/SystemUtils(25437): userId:0
D/SystemUtils(25437): [isSystemApp] begin android.app.Application@da53904
D/ScreenUtils(25437): isMultiWindow:0,userId:0
D/ScreenUtils(25437): hasVivoFreeformTasks:0,userId:0
D/ScreenUtils(25437): isLittleVExist:0,userId:0
D/SystemUtils(25437): userId:0
D/SystemUtils(25437): [isSystemApp] begin android.app.Application@da53904
D/ScreenUtils(25437): isMultiWindow:0,userId:0
D/ScreenUtils(25437): hasVivoFreeformTasks:0,userId:0
D/ScreenUtils(25437): isLittleVExist:0,userId:0
D/SystemUtils(25437): userId:0
W/WindowOnBackDispatcher(25437): OnBackInvokedCallback is not enabled for the application.
W/WindowOnBackDispatcher(25437): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
D/SystemUtils(25437): [isSystemApp] begin android.app.Application@da53904
D/ScreenUtils(25437): isMultiWindow:0,userId:0
D/ScreenUtils(25437): hasVivoFreeformTasks:0,userId:0
D/ScreenUtils(25437): isLittleVExist:0,userId:0
D/SystemUtils(25437): userId:0
D/SystemUtils(25437): [isSystemApp] begin android.app.Application@da53904
D/ScreenUtils(25437): isMultiWindow:0,userId:0
D/ScreenUtils(25437): hasVivoFreeformTasks:0,userId:0
D/ScreenUtils(25437): isLittleVExist:0,userId:0
D/SystemUtils(25437): userId:0
D/SystemUtils(25437): [isSystemApp] begin android.app.Application@da53904
D/ScreenUtils(25437): isMultiWindow:0,userId:0
D/ScreenUtils(25437): hasVivoFreeformTasks:0,userId:0
D/ScreenUtils(25437): isLittleVExist:0,userId:0
D/SystemUtils(25437): userId:0
D/SystemUtils(25437): [isSystemApp] begin android.app.Application@da53904
D/ScreenUtils(25437): isMultiWindow:0,userId:0
D/ScreenUtils(25437): hasVivoFreeformTasks:0,userId:0
D/ScreenUtils(25437): isLittleVExist:0,userId:0
D/SystemUtils(25437): userId:0
D/SystemUtils(25437): [isSystemApp] begin android.app.Application@da53904
D/ScreenUtils(25437): isMultiWindow:0,userId:0
D/ScreenUtils(25437): hasVivoFreeformTasks:0,userId:0
D/ScreenUtils(25437): isLittleVExist:0,userId:0
D/SystemUtils(25437): userId:0
D/SystemUtils(25437): [isSystemApp] begin android.app.Application@da53904
D/ScreenUtils(25437): isMultiWindow:0,userId:0
D/ScreenUtils(25437): hasVivoFreeformTasks:0,userId:0
D/ScreenUtils(25437): isLittleVExist:0,userId:0
D/SystemUtils(25437): userId:0
W/WindowOnBackDispatcher(25437): OnBackInvokedCallback is not enabled for the application.
W/WindowOnBackDispatcher(25437): Set 'android:enableOnBackInvokedCallback="true"' in the application manifest.
D/SystemUtils(25437): [isSystemApp] begin android.app.Application@da53904
D/ScreenUtils(25437): isMultiWindow:0,userId:0
D/ScreenUtils(25437): hasVivoFreeformTasks:0,userId:0
D/ScreenUtils(25437): isLittleVExist:0,userId:0
D/SystemUtils(25437): userId:0
D/SystemUtils(25437): [isSystemApp] begin android.app.Application@da53904
D/ScreenUtils(25437): isMultiWindow:0,userId:0
D/ScreenUtils(25437): hasVivoFreeformTasks:0,userId:0
D/ScreenUtils(25437): isLittleVExist:0,userId:0
D/SystemUtils(25437): userId:0
D/SystemUtils(25437): [isSystemApp] begin android.app.Application@da53904
D/ScreenUtils(25437): isMultiWindow:0,userId:0
D/ScreenUtils(25437): hasVivoFreeformTasks:0,userId:0
D/ScreenUtils(25437): isLittleVExist:0,userId:0
D/SystemUtils(25437): userId:0

尝试使用Get.bottomsheet(),但问题依然存在

共有1个答案

阎博易
2024-08-02

在 GetX 框架中,当你使用 Get.put() 来创建并存储一个控制器时,这个控制器实例会被存储在 GetX 的依赖注入容器中,直到它被显式地从容器中移除或应用程序的生命周期结束。这就是为什么你在多次打开和关闭 BottomSheet 时,SongDetailsBottomsheetControlleronInit()onReady() 方法没有被重新调用,并且 onClose() 方法也没有被调用的原因:因为同一个控制器实例被复用了。

要解决这个问题,你可以在每次需要显示 BottomSheet 时创建一个新的 SongDetailsBottomsheetController 实例,而不是从依赖注入容器中获取它。这里有一种方法来实现这一点:

  1. 移除 Get.put() 的使用:在你的 SongDetailsBottomsheet 构造函数中,不要使用 Get.put() 来创建控制器实例。
  2. 直接在构造函数中创建控制器实例:将控制器作为局部变量或作为 SongDetailsBottomsheet 类的成员变量(但不存储在 GetX 的依赖注入容器中)。
  3. 在 BottomSheet 关闭时手动处理资源释放:由于 showModalBottomSheet 不直接支持关闭回调,你可能需要在 BottomSheet 内部添加一个按钮或逻辑来触发控制器的清理或重新初始化。

下面是一个修改后的示例,展示了如何在每次打开 BottomSheet 时创建一个新的控制器实例:

class SongDetailsBottomsheet extends StatelessWidget {
  final MediaItem track;
  late final SongDetailsBottomsheetController controller;

  SongDetailsBottomsheet({super.key, required this.track}) {
    // 在构造函数中直接创建控制器实例
    controller = SongDetailsBottomsheetController(track: track);
    // 你可以在这里监听控制器的 onClose 或其他生命周期事件
    // 但请注意,BottomSheet 没有直接的方法来检测关闭事件
    // 除非你添加了一个按钮或逻辑来手动触发它
  }

  @override
  Widget build(BuildContext context) {
    // 使用 controller 来进行 UI 更新或逻辑处理
    return SizedBox(
      height: 220,
      child: Column(
        children: [
          // 你的 UI 组件
          Text('Track Title: ${controller.track.title}'), // 假设 MediaItem 有一个 title 属性
        ],
      ),
    );
  }

  @override
  void dispose() {
    // 当 Widget 被销毁时,你可以选择在这里释放控制器资源
    // 但在这个案例中,由于每次打开都会创建一个新的实例,所以可能不需要
    // 除非你在控制器中分配了需要手动释放的资源
    super.dispose();
  }
}

class SongDetailsBottomsheetController {
  final MediaItem track;

  SongDetailsBottomsheetController({required this.track});

  // 你可以在这里添加你的初始化逻辑
  void init() {
    // 初始化代码
    debugPrint('Initialized with track: ${track.title}'); // 假设 MediaItem 有一个 title 属性
  }

  // 你可以在这里添加其他需要的方法
}

// 显示 BottomSheet 的代码保持不变,但每次都会创建一个新的 SongDetailsBottomsheet 实例

请注意,由于 showModalBottomSheet 不提供直接的关闭回调,因此你可能需要在 BottomSheet 内部添加逻辑来触发控制器的某些清理操作。如果你确实需要检测 BottomSheet 的关闭事件,你可以考虑在 BottomSheet 内部添加一个按钮或使用其他 UI 组件来允许用户关闭它,并在该操作触发时执行必要的清理。

另外,请注意,我在上面的示例中移除了对 GetX 依赖注入的使用,因为在这个特定的情况下,每次都需要一个新的控制器实例。如果你仍然想使用 GetX 的功能,你可能需要寻找其他方式来管理控制器的生命周期,而不是简单地使用 Get.put()

 类似资料:
  • 我有一个关于android camerax架构的问题。我使用的是预览视图,效果非常好。问题与片段之间的事务有关。片段1具有previewView。当我切换到fragment2并返回fragment1时,我会再次绑定previewview,使它首先出现黑屏,然后预览显示在屏幕上。我不想看到黑屏。这个问题有什么解决办法吗?

  • 下面的代码片段: 我尝试使用“automatickeepaliveClientMixin和@override bool get wantKeepAlive=>true”-即保持它活动,以便下次调用它时,它不会再次调用initState(),但是它没有工作。

  • 问题内容: 当我运行以下代码时,两个测试用例都变为现实: 预期的行为 test1-成功 test2-失败(按预期该计数将变为3) 实际行为 test1-成功 test2-成功 为什么junit 与每个测试方法都调用。它是junit中的错误或有意提供。 问题答案: 每种测试方法的新实例 对于每种测试方法,将创建Junit的行为的 新实例。 因此,在您的情况下,这两种方法的变量都将具有value ,因

  • 每当从我的要素文件开始执行新方案时,就会启动一个新浏览器。我希望浏览器只在我的第一个场景执行时启动一次,在场景的其余部分,不应打开新的浏览器。 我已经把我的浏览器打开代码写进了类下的注释中。

  • 当我在执行语句后检查分配给的内存地址时,我发现内存内容为0。因为我读到没有将内存初始化为0,所以这是正确的行为吗?

  • 问题内容: 是否可以在运行时重新初始化Spring Bean? 我的Bean使用静态设置,在某些情况下会更改,然后我必须重新初始化Bean。 问题答案: 你可以通过三种方法在spring上下文中更新单例bean,可以选择一种适合你的用例: 在Bean中重新加载方法在Bean中 创建一个方法,该方法将更新/重新加载其属性。根据你的触发器,从spring上下文访问bean,然后调用reload方法更新