Finalizable抽象 接口

不应过早最终化的对象的标记接口。

任何静态类型中包含 Finalizable 的局部变量都保证在执行退出变量作用域的代码块之前始终有效。

一个类型包含 Finalizable 的条件是:

  • 该类型是 Finalizable 的非 Never 子类型,或者
  • 该类型是 T?FutureOr<T>,其中 T 包含 Finalizable

换句话说,在变量引用对象的情况下,可以保证不会认为它是不可达的,即使在最后引用之后,变量自身在其作用域的整个持续期间都认为是活的。

如果没有这个标记接口在变量的类型上,只要变量肯定不再被引用,它的值可能会在完全执行周围作用域之前被垃圾回收。这反过来,可能会触发 NativeFinalizer 来执行回调。当变量的类型包含 Finalizable,则 NativeFinalizer 回调直到使用该变量的当前代码完成才会运行。

例如,在执行 someNativeCall 时保持 finalizable 生存。

void myFunction() {
  final finalizable = MyFinalizable(Pointer.fromAddress(0));
  someNativeCall(finalizable.nativeResource);
}

void someNativeCall(Pointer nativeResource) {
  // ..
}

class MyFinalizable implements Finalizable {
  final Pointer nativeResource;

  MyFinalizable(this.nativeResource);
}

实现了 Finalizable 的类的类方法在方法执行期间保持 this 对象存活。this 的值被当作局部变量处理。

例如,在 myFunction 中执行 someNativeCall 时保持 this 生存。

class MyFinalizable implements Finalizable {
  final Pointer nativeResource;

  MyFinalizable(this.nativeResource);

  void myFunction() {
    someNativeCall(nativeResource);
  }
}

void someNativeCall(Pointer nativeResource) {
  // ..
}

将涉及最终化的逻辑作为实现 Finalizable 的类上的方法来实践是一个好习惯。

如果在一个声明变量的块作用域内部创建了闭包,并且该闭包包含对该变量的任何引用,则变量会一直存活,直到闭包对象存活,或者直到该闭包体的执行完成。

例如,通过闭包对象和闭包体的末尾保持 finalizable 生存。

void doSomething() {
  final resourceAction = myFunction();
  resourceAction(); // `finalizable` is alive until this call returns.
}

void Function() myFunction() {
  final finalizable = MyFinalizable(Pointer.fromAddress(0));
  return () {
    someNativeCall(finalizable.nativeResource);
  };
}

void someNativeCall(Pointer nativeResource) {
  // ..
}

class MyFinalizable implements Finalizable {
  final Pointer nativeResource;

  MyFinalizable(this.nativeResource);
}

仅捕获变量通过闭包存活,而不是所有变量。

例如,没有通过返回的闭包对象保持 finalizable 存活。

void Function() myFunction() {
  final finalizable = MyFinalizable(Pointer.fromAddress(0));
  final nativeResource = finalizable.nativeResource;
  return () {
    someNativeCall(nativeResource);
  };
}

void someNativeCall(Pointer nativeResource) {
  // ..
}

class MyFinalizable implements Finalizable {
  final Pointer nativeResource;

  MyFinalizable(this.nativeResource);
}

如果从最终化对象中提取的资源逃脱了它所取的最终化变量的作用域,那么可能是一个错误。

Finalizable 变量的行为也适用于异步函数。这些变量在其声明的范围或捕获该变量的闭包中仍然存活,即使在该执行期间有异步延迟。

例如,在执行 await someAsyncCall() 时保持 finalizable 生存。

Future<void> myFunction() async {
  final finalizable = MyFinalizable();
  await someAsyncCall();
}

Future<void> someAsyncCall() async {
  // ..
}

class MyFinalizable implements Finalizable {
  // ..
}

在异步代码中,如果从最终化对象中提取的资源逃脱了它所取的最终化变量的作用域,那么可能是一个错误。如果您必须从 Finalizable 中提取资源,您应该通过 await 任何使用该资源的异步代码来确保在最终化定义的范围中超越资源。

例如,在 useAsync1 中,直到不再使用 resource,才保持 this 生存,但在 useAsync2useAsync3 中则不是。

class MyFinalizable {
  final Pointer<Int8> resource;

  MyFinalizable(this.resource);

  Future<int> useAsync1() async {
    return await useResource(resource);
  }

  Future<int> useAsync2() async {
    return useResource(resource);
  }

  Future<int> useAsync3() {
    return useResource(resource);
  }
}

/// Does not use [resource] after the returned future completes.
Future<int> useResource(Pointer<Int8> resource) async {
  return resource.value;
}

异步函数可能在一个 await 点上 挂起,这样运行时系统可以看到该 await 无法完成。在这种情况下,包括 finally 块在内,在 await 之后将不会执行任何代码,变量可能被认为与其他一切一样是死的。

如果您不打算自己保持变量的生存,请确保通过其他函数传递最终化对象,而不是仅仅传递其资源。

例如,finalizablemyFunction运行到其作用域的末尾后不会保持活跃状态,而someAsyncCall仍然可以继续执行。然而,finalizable本身是由someAsyncCall保持活跃的。

void myFunction() {
  final finalizable = MyFinalizable();
  someAsyncCall(finalizable);
}

Future<void> someAsyncCall(MyFinalizable finalizable) async {
  // ..
}

class MyFinalizable implements Finalizable {
  // ..
}
注解
  • @Since('2.17')

属性

hashCode int
此对象的哈希码。
no setterinherited
runtimeType Type
对象的运行时类型表示。
no setterinherited

方法

noSuchMethod(Invocation invocation) → dynamic
当访问不存在的方法或属性时调用。
inherited
toString() String
此对象的字符串表示形式。
inherited

运算符

operator ==(Object other) bool
等号运算符。
inherited