Flutter资源清理插件disposed的使用

Flutter资源清理插件disposed的使用

Disposed 库提供了自动对象清理的包装器,利用了 Finalizer

注意事项

DisposableContainer 中的内部 Disposable 对象 必须 不要强引用其父容器,否则将导致内存泄漏,并且对象不仅永远不会被释放,还会一直保留在内存中直到程序运行结束。

功能特点

  • 使用此包可以创建对象析构函数。

使用方法

以下是一个示例:

// 包含可处置对象,同时也是可处置自身。
class NotificationsProvider extends DisposableContainer implements Disposable {
  final _notificationsController = DisposableStreamController(
    StreamController<String>.broadcast(),
  );

  Stream<String> get notifications => _notificationsController.controller.stream;
 
  void notify(String message) {
    _notificationsController.controller.add(message);
  }

  [@override](/user/override)
  late final List<Disposable> disposables = [ _notificationsController, ];

  [@override](/user/override)
  void dispose() {
    // 注意:这将在 [disposables] 被处置之前调用。
    print('NotificationsProvider is disposed.');
  }
}

// 主容器
class NotificationsCenter extends DisposableContainer {
  NotificationsCenter(this.provider);

  final NotificationsProvider provider;

  void notify(String message) {
    provider.notify(message);
  }

  [@override](/user/override)
  late final List<Disposable> disposables = [ provider, ];
}

当示例中的 NotificationsCenter 实例变得不可访问时,内部的 Finalizer 将按以下顺序释放对象:

  • NotificationsProvider - 内部可处置对象,也是包装器。
  • DisposableStreamController - 内部可处置对象。

注意,NotificationsCenter 本身只是一个包装器(主包装器),它不会被处置,而是由语言的垃圾回收器进行垃圾收集。

这种顺序是因为父对象引用了子对象,因此垃圾回收器会先销毁父对象,然后子对象失去引用,也会被销毁。

完整示例代码

/// 在此示例中,我们将创建一个包含通知提供者的通知中心。
/// 
/// 这将说明如何创建自动关闭的 [Stream]。
library disposed_example;

import 'dart:async';

import 'package:disposed/disposed.dart';

class NotificationsProvider extends DisposableContainer implements Disposable {
  final _notificationsController = DisposableStreamController(
    StreamController<String>.broadcast(),
  );

  Stream<String> get notifications => _notificationsController.controller.stream;
 
  void notify(String message) {
    _notificationsController.controller.add(message);
  }

  [@override](/user/override)
  late final List<Disposable> disposables = [ _notificationsController, ];

  [@override](/user/override)
  void dispose() {
    // 注意:这将在 [disposables] 被处置之前调用。
    print('NotificationsProvider is disposed.');
  }
}

class NotificationsCenter extends DisposableContainer {
  NotificationsCenter(this.provider);

  final NotificationsProvider provider;

  void notify(String message) {
    provider.notify(message);
  }

  [@override](/user/override)
  late final List<Disposable> disposables = [ provider, ];
}

Future<void> main(List<String> args) async {
  // 创建对象。
  NotificationsProvider? provider = NotificationsProvider();
  NotificationsCenter? center = NotificationsCenter(provider);

  // 通过弱引用跟踪GC状态。
  final _provider = WeakReference(provider);
  final _center = WeakReference(center);

  // 监听一些通知。
  center.provider.notifications.listen(
    (event) => print('New notification: $event'),
    onDone: () => print('Notifications done.'),
  );

  // 执行一些操作。
  center.notify('Test!');
  await Future<void>.delayed(const Duration(milliseconds: 250));
  center.notify('Test 2!');

  // 使对象不可访问。
  provider = null;
  center = null;

  // 等待GC。
  while (_provider.target != null || _center.target != null) {
    await Future<void>.delayed(const Duration(milliseconds: 1));
    // 喂养内存以强制GC。
    // ignore: unused_local_variable
    final bigChunkOfData = '0' * 1024 * 1024 * 5; // 大约5MB的数据。
  }

  print('Disposables are disposed, objects garbage collected, streams closed.');
}

更多关于Flutter资源清理插件disposed的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter资源清理插件disposed的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是一个关于如何在Flutter应用中使用disposed插件进行资源清理的示例。disposed插件(假设这是一个虚构的插件名称,因为Flutter官方并没有一个名为disposed的插件,但类似功能可以通过自定义逻辑实现)通常用于在Widget被销毁时清理资源,比如取消网络请求、停止动画、释放内存等。

在Flutter中,我们可以通过Disposable接口或者类似机制来实现资源清理。虽然没有一个现成的disposed插件,但你可以通过实现Disposable接口和重写dispose方法来达到相同的效果。

以下是一个示例代码,展示如何在Flutter中自定义资源清理逻辑:

  1. 创建一个可释放资源的类
class CustomResource {
  // 模拟一个需要清理的资源,比如一个计时器
  Timer? _timer;

  CustomResource(Duration interval, VoidCallback callback) {
    _timer = Timer.periodic(interval, callback);
  }

  // 清理资源的方法
  void dispose() {
    _timer?.cancel();
    _timer = null;
    print("CustomResource disposed");
  }
}
  1. 创建一个Widget并使用资源清理逻辑
import 'package:flutter/material.dart';

class ResourceWidget extends StatefulWidget {
  @override
  _ResourceWidgetState createState() => _ResourceWidgetState();
}

class _ResourceWidgetState extends State<ResourceWidget> with WidgetsBindingObserver {
  CustomResource? _resource;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance?.addObserver(this);

    // 初始化资源
    _resource = CustomResource(Duration(seconds: 5), () {
      print("Timer ticked");
    });
  }

  @override
  void dispose() {
    // 清理资源
    _resource?.dispose();
    _resource = null;

    WidgetsBinding.instance?.removeObserver(this);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Resource Cleanup Example'),
      ),
      body: Center(
        child: Text('This widget will clean up resources when disposed.'),
      ),
    );
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    // 这个方法通常用于处理应用生命周期的变化,但在这个例子中我们不需要它
    super.didChangeAppLifecycleState(state);
  }
}

void main() {
  runApp(MaterialApp(
    home: ResourceWidget(),
  ));
}

在这个示例中,我们创建了一个CustomResource类,它包含一个Timer,并在dispose方法中取消该计时器。然后,我们在ResourceWidget中创建并管理这个资源。在dispose方法中,我们确保在Widget被销毁时调用_resource?.dispose()来清理资源。

请注意,虽然这个示例没有直接使用一个名为disposed的插件,但它展示了如何在Flutter中实现资源清理的逻辑。如果你确实有一个特定的disposed插件,并且需要更详细的用法,请参考该插件的官方文档或示例代码。

回到顶部