Flutter:从另一个 class 将 BuildContext 设置为 null

Flutter: Setting BuildContext to null from another class

我想知道如何使另一个 class 中的 BuildContext 无效,以防止它在处理上下文的小部件后被异步函数使用。

我假设它是通过引用传递的,所以我尝试在原始小部件中将它设置为 null(在我的用例中,我在 dispose 方法中将它设置为 null 并且onWillPop 方法,两者都无济于事)。我为我想做的事情创建了一个简单的示例应用程序。如您所见,如果您 运行 应用程序,则上下文未设置为 null

import 'dart:async';

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Setting BuildContext to null',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Setting BuildContext to null'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  AsyncClass _asyncClass = AsyncClass();
  Duration duration = const Duration(seconds: 5);
  void toggleContext(BuildContext context){
    Timer.periodic(duration, (_){
      print("Setting context to null");
      context = null;

    });
  }

  @override
  Widget build(BuildContext context) {
    toggleContext(context);
    _asyncClass.asyncFunc(context);
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(),
    );
  }
}

class AsyncClass{
  void asyncFunc(BuildContext context){
    const duration = const Duration(seconds: 1);
    Timer.periodic(duration, (_){
      if(context==null){
        print("Context is null");
      } else {
        print("Context is not null");
      }

    });
  }
}
asyncFunc 中的

context 只是对 Dart 堆上原始 BuildContext 对象的引用的副本,因此将 context 设置为 null 只会设置那个特定变量为 null,而不是所有具有相同引用的变量。

如果您来自 C/C++ 背景,您所做的更像是更改指针的地址值,而不是更改指针指向的地址处的值.

编辑: 一个潜在的解决方案是做这样的事情:

class AsyncClass{
  BuildContext context;
  void asyncFunc(BuildContext param){
    context = param;
    const duration = const Duration(seconds: 1);
    Timer.periodic(duration, (_){
      if(context==null){
        print("Context is null");
      } else {
        print("Context is not null");
      }
    });
  }
}

然后这样做:

  void toggleContext(BuildContext context){
    Timer.periodic(duration, (_){
      print("Setting context to null");
      _asyncClass.context = null;
    });
  }

我发现我可以使用 ValueParameter class 来包装 BuildContext 对象。这使我可以非常简单地将新的 ValueParameter 值传递给函数,并很容易地从它包含的任何函数中将它们全部设置为 null

这是我的解决方案(我添加了 if(_timer==null) 以防止在应用程序刷新时形成重复的 Timer)。

import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Setting BuildContext to null',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Setting BuildContext to null'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  AsyncClass _asyncClass = AsyncClass();
  Duration duration = const Duration(seconds: 5);
  Timer _timer;
  void toggleContext(ValueNotifier context) {
    if (_timer == null)
      _timer = Timer.periodic(duration, (_) {
        print("Setting context to null");
        context.value = null;
      });
  }

  @override
  Widget build(BuildContext param) {
    ValueNotifier context = ValueNotifier(param);
    toggleContext(context);
    _asyncClass.asyncFunc(context);
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(),
    );
  }
}

class AsyncClass {
  Timer _timer;
  void asyncFunc(ValueNotifier context) {
    const duration = const Duration(seconds: 1);
    if (_timer == null)
      _timer = Timer.periodic(duration, (_) {
        if (context.value == null) {
          print("Context is null");
        } else {
          print("Context is not null");
        }
      });
  }
}