fix: use internal Set for determining first ThermionTextureWidget to call requestFrame and cleanup destruction logic

This commit is contained in:
Nick Fisher
2024-10-22 12:47:13 +08:00
parent 58e549e3b3
commit 0c29d61a35

View File

@@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
import 'package:thermion_dart/src/viewer/src/shared_types/view.dart' as t; import 'package:thermion_dart/src/viewer/src/shared_types/view.dart' as t;
import 'package:thermion_flutter/src/widgets/src/resize_observer.dart'; import 'package:thermion_flutter/src/widgets/src/resize_observer.dart';
import 'package:thermion_flutter/thermion_flutter.dart'; import 'package:thermion_flutter/thermion_flutter.dart';
@@ -42,15 +43,17 @@ class ThermionTextureWidget extends StatefulWidget {
class _ThermionTextureWidgetState extends State<ThermionTextureWidget> { class _ThermionTextureWidgetState extends State<ThermionTextureWidget> {
ThermionFlutterTexture? _texture; ThermionFlutterTexture? _texture;
RenderTarget? _renderTarget;
static final _views = <t.View>[]; static final _views = <t.View>[];
final _logger = Logger("_ThermionTextureWidgetState");
@override @override
void dispose() { void dispose() {
super.dispose(); super.dispose();
_views.remove(widget.view); _views.remove(widget.view);
_texture?.destroy(); _texture?.destroy();
_states.remove(this);
} }
@override @override
@@ -79,14 +82,16 @@ class _ThermionTextureWidgetState extends State<ThermionTextureWidget> {
widget.view, widget.view,
dpr); dpr);
} catch (err, st) { } catch (err, st) {
print(err); _logger.severe(err);
print(st); _logger.severe(st);
} }
if (mounted) { if (mounted) {
setState(() {}); setState(() {});
} }
_states.add(this);
_requestFrame(); _requestFrame();
widget.viewer.onDispose(() async { widget.viewer.onDispose(() async {
@@ -98,23 +103,39 @@ class _ThermionTextureWidgetState extends State<ThermionTextureWidget> {
_views.clear(); _views.clear();
}); });
}); });
_callbackId = _numCallbacks;
_numCallbacks++;
super.initState(); super.initState();
} }
bool _rendering = false; bool _rendering = false;
static int _numCallbacks = 0; static final _states = <_ThermionTextureWidgetState>{};
static int _primaryCallback = 0;
late int _callbackId;
int lastRender = 0; int lastRender = 0;
///
/// Each instance of ThermionTextureWidget in the widget hierarchy must
/// call[markFrameAvailable] on every frame to notify Flutter that the content
/// of its backing texture has changed.
///
/// Calling [requestFrame] on [ThermionViewer], however, will render all
/// views/swapchains that have been marked as renderable (see [setRenderable]).
///
/// Only need one instance of [ThermionTextureWidget] needs to call
/// [requestFrame]. We manage this by storing all instances of
/// [_ThermionTextureWidgetState] in a static set, and allowing the first
/// instance to call [requestFrame].
///
void _requestFrame() { void _requestFrame() {
if (!mounted) {
return;
}
WidgetsBinding.instance.scheduleFrameCallback((d) async { WidgetsBinding.instance.scheduleFrameCallback((d) async {
if (!mounted) {
return;
}
if (widget.viewer.rendering && !_rendering) { if (widget.viewer.rendering && !_rendering) {
_rendering = true; _rendering = true;
if (_callbackId == _primaryCallback && _texture != null) { if (this == _states.first && _texture != null) {
await widget.viewer.requestFrame(); await widget.viewer.requestFrame();
lastRender = d.inMilliseconds; lastRender = d.inMilliseconds;
} }