Android

关注公众号 jb51net

关闭
首页 > 软件编程 > Android > Flutter中灰屏问题

Flutter中灰屏问题的原因及解决方法

作者:独立开发者张张

生产中的 flutter 应用程序中的灰屏是一种通用占位符,当框架遇到问题无法渲染预期用户界面时就会显示,所以基本上是出现问题时的后备指示器,本文给大家介绍了Flutter中灰屏问题的原因及解决方法,需要的朋友可以参考下

生产中的 flutter 应用程序中的灰屏是一种通用占位符,当框架遇到问题无法渲染预期用户界面时就会显示。是的,所以基本上是出现问题时的后备指示器。

有趣的是,这只出现在发布模式下。在任何其他模式下运行都会显示红色错误屏幕,并说明导致错误的原因。 (检查此处以了解各种类型的构建模式。)此类错误的常见原因是:

以下是可能导致灰屏的代码示例:

class HomeView extends HookWidget {
  const HomeView({super.key});
  @override
  Widget build(BuildContext context) {
    const widget = null;
    return Scaffold(
      appBar: AppBar(
        title: Text(
          'Gallery',
          style: Theme.of(context).textTheme.headlineLarge,
        ),
      ),
      body: widget!,
    );
  }
}

在这里,我们犯了一个明显的错误,在我们知道的 null 小部件上使用了 bang 运算符(!),这导致在非发布模式下出现红屏,在发布模式下出现灰屏。

需要注意的是,我们不建议在不更新的情况下将部件明确设置为空值,空值错误是一个常见错误,而上述操作是重现该错误的简单方法。

调试模式下的红色错误屏幕(左)和发布模式下的灰色屏幕(右)的图像

自定义错误屏幕

为了显示更用户友好的消息而不是灰屏,我们将策略性地在 main 函数中放置一行代码。该行充当预防措施,确保每当发生未处理的异常时都会显示自定义错误屏幕。

void main() {
  ErrorWidget.builder = (_) => const AppErrorWidget(); // This line does the magic!
  runApp(MyApp());
}

有条件的红屏(可选):

也许您希望在开发过程中看到默认的红色错误屏幕以进行调试。您可以通过将 ErrorWidget.builder 赋值包装在检查当前构建模式的 if 语句中来实现此目的:

void main() {
  if (kReleaseMode) ErrorWidget.builder = (_) => const AppErrorWidget();
  runApp(MyApp());
}

下一步涉及创建 AppErrorWidget 本身的内容。该小部件将确定发生未处理的异常时用户看到的内容。

class AppErrorWidget extends StatelessWidget {
  const AppErrorWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return const Material(
      color: Colors.white,
      child: Padding(
        padding: EdgeInsets.all(24),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          mainAxisSize: MainAxisSize.min,
          children: [
            Icon(
              Icons.warning,
              size: 200,
              color: Colors.amber,
            ),
            SizedBox(height: 48),
            Text(
              'So... something funny happened',
              textAlign: TextAlign.center,
              style: TextStyle(
                fontSize: 24,
                fontWeight: FontWeight.bold,
              ),
            ),
            SizedBox(height: 16),
            Text(
              'This error is crazy large it covers your whole screen. But no worries'
              ' though, we\'re working to fix it.',
              textAlign: TextAlign.center,
              style: TextStyle(
                fontSize: 16,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

虽然鼓励自定义应用程序的体验,但 ErrorWidget.builder 上的 Flutter 文档提醒我们,调用错误小部件时视图处于不稳定状态。构建(可能还有布局)期间的异常会使系统处于脆弱状态。为了最大限度地减少进一步的问题,返回的小部件应该做最少的工作。 LeafRenderObjectWidget (如默认的 RenderErrorBox )非常适合处理意外约束。

ErrorWidget.builder 的幕后花絮

现在我们知道,当渲染预期 UI 的过程中发生错误时, ErrorWidget.builder 就会被调用,但是这到底是如何实现的呢?

如果我们深入研究 Flutter 的框架,我们会在构建或重建小部件时看到一个名为 _updateChild() 的方法。

void _updateChild() {
  try {
    final Widget child = (widget as _RawView).builder(this, _effectivePipelineOwner);
    _child = updateChild(_child, child, null);
  } catch (e, stack) {
    final FlutterErrorDetails details = FlutterErrorDetails(
      exception: e,
      stack: stack,
      library: 'widgets library',
      context: ErrorDescription('building $this'),
      informationCollector: !kDebugMode ? null : () => <DiagnosticsNode>[
        DiagnosticsDebugCreator(DebugCreator(this)),
      ],
    );
    FlutterError.reportError(details);
    final Widget error = ErrorWidget.builder(details);
    _child = updateChild(null, error, slot);
  }
}

我们可以看到 ErrorWidget.builder 属性用于根据提供的 FlutterErrorDetails 检索自定义错误小部件;然后更新 _child 变量以显示自定义错误小部件而不是原始子小部件。

提升开发者体验

定制向用户呈现错误的方式是改善用户体验的关键一步。虽然 ErrorWidget.builder 帮助我们在出现错误时管理用户体验,但它并没有为生产环境中的开发人员提供有价值的见解。本地调试不再是一种选择,那么我们如何及时了解用户设备上发生的错误呢?

这就是我们利用 FlutterError.onError 回调的力量的地方。让我们看看这是如何完成的:

void main() {
  if (kReleaseMode) ErrorWidget.builder = (_) => const AppErrorWidget();

  FlutterError.onError = (details) {
    FlutterError.dumpErrorToConsole(details);
    if (!kReleaseMode) return;
    // 发送到您的 crashlytics 服务...
  };

  runApp(MyApp());
}

我们添加了一行新代码,它将新的回调函数分配给 FlutterError.onError 属性。每当使用 FlutterError.reportError 报告错误时都会调用此回调。

在回调内部, FlutterError.dumpErrorToConsole(details) 通过将错误详细信息转储到控制台来帮助我们了解幕后情况。这对于在部署或分阶段部署期间可能存在对用户设备的访问受限的调试目的非常有用。

最后的注释行 ( // 发送到您的 crashlytics 服务... ) 强调了这种方法的真正威力。在这里,您可以集成您选择的错误报告服务(例如 Crashlytics)以发送详细的错误报告以供分析。

注意:此行包含在 if 语句中,以确保它仅在调试或分析模式下执行 ( !kReleaseMode )。

避免灰屏的最佳错误处理实践

我们已经了解了导致灰屏的原因以及出现灰屏时如何更好地处理它;我们还应该介绍的一件事是,作为开发人员可以采取哪些措施来避免出现灰屏。其中一些是:

结论:拥抱不可避免的事情

错误处理是任何编写良好的 Flutter 应用程序的重要组成部分。当您努力编写干净的代码并预测潜在问题时,异常情况必然会发生。通过实施 ErrorWidget.builder ,您可以确保即使发生意外情况,您的用户也会看到清晰且内容丰富的消息,而不是令人困惑的灰屏,并且通过 FlutterError.onError 您可以确保您记录这些意外错误,并且可以更轻松地调试和修复这些错误。

以上就是Flutter中灰屏问题的原因及解决方法的详细内容,更多关于Flutter中灰屏问题的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文