DidChangeMetrics Has Bug

by ADMIN 25 views

问题描述

在使用 WebF 库时,遇到一个问题。在 Page 组件中使用 WebF 控制器,能够正常显示 HTML 布局,并且可以通过键盘调整布局。但是,当返回到 Page 组件时,会出现 A disposed RenderObject was mutated 的错误。

错误信息

[ERROR:flutter/runtime/dart_vm_initializer.cc(40)] Unhandled Exception: A disposed RenderObject was mutated.
The disposed RenderObject was:
  RenderViewportBox#fb351 DISPOSED
#0      RenderObject._debugCanPerformMutations.<anonymous closure> (package:flutter/src/rendering/object.dart:1987:9)
#1      RenderObject._debugCanPerformMutations (package:flutter/src/rendering/object.dart:2095:6)
#2      RenderObject.markNeedsLayout (package:flutter/src/rendering/object.dart:2327:12)
#3      RenderBox.markNeedsLayout (package:flutter/src/rendering/box.dart:2669:11)
#4      RenderViewportBox.bottomInset= (package:webf/src/rendering/viewport.dart:59:7)
#5      WebFViewController.didChangeMetrics (package:webf/src/launcher/controller.dart:808:15)
#6      WidgetsBinding.handleMetricsChanged (package:flutter/src/widgets/binding.dart:755:16)
#7      _invoke (dart:ui/hooks.dart:312:13)
#8      PlatformDispatcher._updateWindowMetrics (dart:ui/platform_dispatcher.dart:316:5)
#9      _updateWindowMetrics (dart:ui/hooks<…>

问题原因

问题的原因是 didChangeMetrics 方法中,尝试访问已经被销毁的 RenderObject。具体来说,是 viewport?.bottomInset = bottomInsets; 这一行代码引起了问题。

解决方案

为了解决这个问题,我们需要在 didChangeMetrics 方法中,检查 viewport 是否为 null 之前,才尝试访问它的 bottomInset 属性。

@override
void didChangeMetrics() {
  final ownerView = rootController.ownerFlutterView;
  final bool resizeToAvoidBottomInsets = rootController.resizeToAvoidBottomInsets;
  final double bottomInsets;
  if (resizeToAvoidBottomInsets) {
    bottomInsets = ownerView.viewInsets.bottom / ownerView.devicePixelRatio;
  } else {
    bottomInsets = 0;
  }

  if (resizeToAvoidBottomInsets && viewport?.hasSize == true) {
    bool shouldScrollByToCenter = false;
    Element? focusedElement = document.focusedElement;
    double scrollOffset = 0;
    if (focusedElement != null) {
      RenderBox? renderer = focusedElement.renderer;
      if (renderer != null && renderer.attached && renderer.hasSize) {
        Offset focusOffset = renderer.localToGlobal(Offset.zero);
        // FOCUS_VIEWINSET_BOTTOM_OVERALL to meet border case.
        if (focusOffset.dy > viewport!.size.height - bottomInsets - FOCUS_VIEWINSET_BOTTOM_OVERALL) {
          shouldScrollByToCenter = true;
          scrollOffset =
              focusOffset.dy - (viewport!.size.height - bottomInsets) + renderer.size.height + FOCUS_VIEWINSET_BOTTOM_OVERALL;
        }
      }
    }
    // Show keyboard
    if (shouldScrollByToCenter) {
      window.scrollBy(0, scrollOffset, false);
    }
  }
  window.resizeViewportRelatedElements();
  if (viewport != null) {
    viewport.bottomInset = bottomInsets;
  }
}

其他问题

WebF 库中,遇到另一个问题。在 WebFController 中,尝试访问 view.document.documentElement!.applyStyle(view.document.documentElement!.style); 时,会出现 Null check operator used on a null value 的错误。

// Manually initialize the root element and create renderObjects for each elements.
view.document.documentElement!.applyStyle(view.document.documentElement!.style);

解决方案

为了解决这个问题,我们需要检查 view.document.documentElement 是否为 null 之前,才尝试访问它的 applyStyle 方法。

// Manually initialize the root element and create renderObjects for each elements.
if (view.document.documentElement != null) {
  view.document.documentElement!.applyStyle(view.document.documentElement!.style);
}

总结

问题描述

在使用 WebF 库时,遇到一个问题。在 Page 组件中使用 WebF 控制器,能够正常显示 HTML 布局,并且可以通过键盘调整布局。但是,当返回到 Page 组件时,会出现 A disposed RenderObject was mutated 的错误。

错误信息

[ERROR:flutter/runtime/dart_vm_initializer.cc(40)] Unhandled Exception: A disposed RenderObject was mutated.
The disposed RenderObject was:
  RenderViewportBox#fb351 DISPOSED
#0      RenderObject._debugCanPerformMutations.<anonymous closure> (package:flutter/src/rendering/object.dart:1987:9)
#1      RenderObject._debugCanPerformMutations (package:flutter/src/rendering/object.dart:2095:6)
#2      RenderObject.markNeedsLayout (package:flutter/src/rendering/object.dart:2327:12)
#3      RenderBox.markNeedsLayout (package:flutter/src/rendering/box.dart:2669:11)
#4      RenderViewportBox.bottomInset= (package:webf/src/rendering/viewport.dart:59:7)
#5      WebFViewController.didChangeMetrics (package:webf/src/launcher/controller.dart:808:15)
#6      WidgetsBinding.handleMetricsChanged (package:flutter/src/widgets/binding.dart:755:16)
#7      _invoke (dart:ui/hooks.dart:312:13)
#8      PlatformDispatcher._updateWindowMetrics (dart:ui/platform_dispatcher.dart:316:5)
#9      _updateWindowMetrics (dart:ui/hooks<…>

问题原因

问题的原因是 didChangeMetrics 方法中,尝试访问已经被销毁的 RenderObject。具体来说,是 viewport?.bottomInset = bottomInsets; 这一行代码引起了问题。

解决方案

为了解决这个问题,我们需要在 didChangeMetrics 方法中,检查 viewport 是否为 null 之前,才尝试访问它的 bottomInset 属性。

@override
void didChangeMetrics() {
  final ownerView = rootController.ownerFlutterView;
  final bool resizeToAvoidBottomInsets = rootController.resizeToAvoidBottomInsets;
  final double bottomInsets;
  if (resizeToAvoidBottomInsets) {
    bottomInsets = ownerView.viewInsets.bottom / ownerView.devicePixelRatio;
  } else {
    bottomInsets = 0;
  }

  if (resizeToAvoidBottomInsets && viewport?.hasSize == true) {
    bool shouldScrollByToCenter = false;
    Element? focusedElement = document.focusedElement;
    double scrollOffset = 0;
    if (focusedElement != null) {
      RenderBox? renderer = focusedElement.renderer;
      if (renderer != null && renderer.attached && renderer.hasSize) {
        Offset focusOffset = renderer.localToGlobal(Offset.zero);
        // FOCUS_VIEWINSET_BOTTOM_OVERALL to meet border case.
        if (focusOffset.dy > viewport!.size.height - bottomInsets - FOCUS_VIEWINSET_BOTTOM_OVERALL) {
          shouldScrollByToCenter = true;
          scrollOffset =
              focusOffset.dy - (viewport!.size.height - bottomInsets) + renderer.size.height + FOCUS_VIEWINSET_BOTTOM_OVERALL;
        }
      }
    }
    // Show keyboard
    if (shouldScrollByToCenter) {
      window.scrollBy(0, scrollOffset, false);
    }
  }
  window.resizeViewportRelatedElements();
  if (viewport != null) {
    viewport.bottomInset = bottomInsets;
  }
}

其他问题

WebF 库中,遇到另一个问题。在 WebFController 中,尝试访问 view.document.documentElement!.applyStyle(view.document.documentElement!.style); 时,会出现 Null check operator used on a null value 的错误。

// Manually initialize the root element and create renderObjects for each elements.
view.document.documentElement!.applyStyle(view.document.documentElement!.style);

解决方案

为了解决这个问题,我们需要检查 view.document.documentElement 是否为 null 之前,才尝试访问它的 applyStyle 方法。

// Manually initialize the root element and create renderObjects for each elements.
if (view.document.documentElement != null) {
  view.document.documentElement!.applyStyle(view.document.documentElement!.style);
}

Q&A

Q: 什么是 didChangeMetrics 方法? A: didChangeMetrics 方法是 WebF 库中一个重要的方法,它用于处理窗口大小和位置的变化。

Q: 为什么会出现 A disposed RenderObject was mutated 的错误? A: 这个错误是因为 didChangeMetrics 方法中,尝试访问已经被销毁的 RenderObject

Q: 如何解决这个问题? A: 需要在 didChangeMetrics 方法中,检查 viewport 是否为 null 之前,才尝试访问它的 bottomInset 属性。

Q: 在 WebFController 中,尝试访问 view.document.documentElement!.applyStyle(view.document.documentElement!.style); 时,会出现 Null check operator used on a null value 的错误。如何解决这个问题? A: 需要检查 view.document.documentElement 是否为 null 之前,才尝试访问它的 applyStyle 方法。

Q: WebF 库中,遇到哪些其他问题? A: 在 WebF 库中,遇到其他问题,例如 Null check operator used on a null value 的错误。

Q: 如何解决这些问题? A: 需要检查相关的属性或方法是否为 null 之前,才尝试访问它们。