Flutter资源管理插件dispose的使用

Flutter资源管理插件dispose的使用

你是否厌倦了必须取消订阅、停止定时器并关闭控制器?
你是否曾经创建过一个Angular组件或Flutter小部件,其中某个流正在被监听或定时器仍在运行,即使在组件或小部件被销毁后?

那么你可能需要将一个变量绑定到订阅上,以便在组件销毁时可以取消它吗?
更不用说,如果你的定时器/流是唯一的,你需要在重新赋值之前取消它。

所有这些都发生是因为你的组件/小部件与流/定时器/控制器之间没有真正的连接。
好吧,这个包旨在帮助你解决这个问题。

该包提供了一个Disposable类,它有一个dispose()函数,用于清除在其内部创建的所有监听器、定时器、控制器等。你可以通过设置参数Symbol uniqueId来使对象唯一。

还有一个Angular类,它在OnDestroy时自动处理清理工作(package:dispose/angular.dart)。

在下面的例子中,你必须在某个地方调用SomeClassdispose()方法。通常是在小部件/组件销毁时。

示例:

import 'package:dispose/dispose.dart';  

each

遍历流并在dispose()中清理监听器。
示例:

class SomeClass extends Disposable {  
  void listenToInts(Stream<int> myIntStream) {  
    each(myIntStream, (int value) {  
      print('someInt $value');  
    }, uniqueId: #MyUniqueListener);  
  }  
}

controller

创建一个StreamController<T>,并在dispose()中关闭它。
示例:

class SomeClass extends Disposable {  
  late StreamController<int> _intController;  
    
  SomeClass() {  
    _intController = controller(broadcast: false);  
  }  
}

timer

创建一个Timer,如果它尚未执行,则在dispose()中取消它。
示例:

class SomeClass extends Disposable {  
  void method() {  
    timer(Duration(seconds: 5), () => print('Executed!'));  
    // 如果未执行,上述定时器将在dispose()中被取消  
  }  
}

periodic

创建一个Timer.periodic,并在dispose()中取消它。
示例:

class SomeClass extends Disposable {  
  void method() {  
    var x = 0;  
    periodic(Duration(seconds: 5), () => print('Executed ${++x}'));  
  }  
}

bind

绑定另一个Disposable对象,它将在dispose()中被释放。
示例:

class SomeOtherClass extends Disposable {
  Timer myPeriodic;
  SomeOtherClass() {
    myPeriodic = periodic(Duration(seconds: 30));
  }
}  

class SomeClass extends Disposable {  
  final prop = SomeOtherClass();

  SomeClass() {
    // 如果prop尚未被释放,它将在SomeClass.dispose()中被释放
    bind(prop);
  }
}

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

1 回复

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


在Flutter开发中,资源管理是一个非常重要的环节,特别是当你使用大量的图像、音频或其他资源时。为了有效管理这些资源,避免内存泄漏,dispose方法通常被用来释放资源。在Flutter中,dispose方法常用于StatefulWidget中的State对象,或者当你使用某些需要手动释放资源的插件时。

虽然Flutter本身并没有一个名为“资源管理插件”的官方插件,但我们可以讨论如何在使用图片资源或第三方插件时正确实现dispose方法。这里,我将提供一个简单的示例,展示如何在Flutter中使用dispose方法来释放资源。

示例:使用ImageProvider和dispose

假设我们有一个屏幕,它显示了一张图片,并且图片资源是通过网络获取的。为了管理这个图片资源,我们可以在组件销毁时释放它(虽然Flutter的垃圾回收机制通常会处理这些,但手动释放是一个好习惯)。

import 'package:flutter/material.dart';
import 'dart:ui' as ui;

class ImageScreen extends StatefulWidget {
  @override
  _ImageScreenState createState() => _ImageScreenState();
}

class _ImageScreenState extends State<ImageScreen> {
  ui.Image? _image;
  ImageProvider? _imageProvider;

  @override
  void initState() {
    super.initState();
    // 假设我们有一个网络图片的URL
    String imageUrl = 'https://example.com/path/to/image.jpg';
    _imageProvider = NetworkImage(imageUrl);

    // 预加载图片到内存中
    preloadImage(_imageProvider!).then((value) {
      setState(() {
        _image = value;
      });
    });
  }

  Future<ui.Image> preloadImage(ImageProvider image) async {
    final Completer<ui.Image> completer = Completer<ui.Image>();
    image.resolve(createLocalImageConfiguration(context)).addListener(
      ImageStreamListener((ImageInfo imageInfo, bool synchronousCall) {
        final ui.Image uiImage = imageInfo.image;
        if (!completer.isCompleted) {
          completer.complete(uiImage);
        }
      }),
    );
    return completer.future;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Image Screen')),
      body: Center(
        child: _image != null
            ? CustomPaint(
                size: Size.square(300),
                painter: ImagePainter(_image!),
              )
            : CircularProgressIndicator(),
      ),
    );
  }

  @override
  void dispose() {
    // 如果ImageProvider有特殊的资源需要释放(虽然NetworkImage通常不需要),
    // 可以在这里进行。在这个例子中,我们主要演示dispose的用法。
    // _imageProvider?.evict(); // NetworkImage没有evict方法,这只是一个假设示例。
    super.dispose();
  }
}

class ImagePainter extends CustomPainter {
  final ui.Image image;

  ImagePainter(this.image);

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()..isAntiAlias = true;
    canvas.drawImage(image, Offset.zero, paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }
}

注意

  1. NetworkImage: 在上面的例子中,NetworkImage其实不需要手动释放资源,因为Flutter会管理这些。但是,如果你使用了一些自定义的ImageProvider或者第三方插件,它们可能提供了evict或其他释放资源的方法。
  2. CustomPainter: 在这个例子中,我们使用CustomPainter来绘制预加载的图片,这只是为了展示如何使用ui.Image
  3. dispose方法: 在dispose方法中,我们没有实际释放NetworkImage的资源,因为这不是必需的。但是,如果你使用的是需要手动释放资源的对象,你应该在这里调用相应的释放方法。

在实际开发中,你可能会遇到更多需要手动管理资源的场景,比如视频播放、音频播放、大型数据集等。在这些情况下,确保在组件销毁时正确释放资源是非常重要的。

回到顶部