Flutter 小部件状态未更新 - 抛出“查找已停用小部件的祖先是不安全的”

lil*_*uit 9 flutter

我正在尝试使用此示例在 Flutter 中实现登录/注销。登录工作正常,控制台输出为:

flutter: LOGIN WIDGET BUILD CONTEXT:
flutter: LoginScreen(dirty, state: LoginScreenState#552db)
flutter: _ctx:
flutter: LoginScreen(state: LoginScreenState#552db)
Run Code Online (Sandbox Code Playgroud)

但是注销后,我无法重新登录(上下文丢失)。注销然后尝试重新登录后,onAuthStateChanged()注销后其中的上下文丢失:

flutter: LOGIN WIDGET BUILD CONTEXT:
flutter: LoginScreen(dirty, state: LoginScreenState#d112e)
flutter: _ctx
flutter: LoginScreen
Run Code Online (Sandbox Code Playgroud)

login.dart

class LoginScreen extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return new LoginScreenState();
  }
}
class LoginScreenState extends State<LoginScreen>

   BuildContext _ctx;

   @override
   onAuthStateChanged(AuthState state) {
      print("_ctx");
      print(_ctx.toString());   
      if(state == AuthState.LOGGED_IN) { 
         print("ready to login");
         Navigator.of(_ctx).pushReplacementNamed("/home");  
      } 
   }

   @override
   Widget build(BuildContext context) {
      _ctx = context;
      print("LOGIN WIDGET BUILD CONTEXT:");
      print(_ctx.toString());
   }
}
Run Code Online (Sandbox Code Playgroud)

home.dart

class Settings extends StatelessWidget {

  @override
  Widget build(BuildContext context) => new Container(
    child: new ListView(
        children: <Widget>[
          new ListTile(
            //leading: Icon(Icons.map),
            title: new Text('About')
          ),
          new ListTile(
            //leading: Icon(Icons.photo_album),
            title: new Text('Logout'),
            onTap: () {
               Navigator.of(context).pushReplacementNamed("/login");
            }
          )
        ],
      ),
    );  
Run Code Online (Sandbox Code Playgroud)

路线:

final routes = {
  '/login': (BuildContext context) => new LoginScreen(),
  '/home': (BuildContext context) => new Tabs(),
  '/' : (BuildContext context) => new LoginScreen(),
};
Run Code Online (Sandbox Code Playgroud)

Wy 未_ctx更新,onAuthStateChanged()是否有更好的方法来处理登录状态?

kuh*_*yal 5

您正在重用旧BuildContext实例。不要在build方法中保存实例。你永远不应该这样做。

LoginScreen是 aStatefulWidget并且它的状态 ( LoginScreenState) 已经拥有context属性。尝试改用它。

您还需要配置侦听器,示例中已经有了dispose(AuthListener)可以使用的方法。

@override
void dispose() {
  super.dispose(); // always call super for dispose/initState
  AuthStateProvider().dispose(this);
}
Run Code Online (Sandbox Code Playgroud)

一般来说,这个例子已经很老了,我建议找一个更新的教程。Flutter 和 Dart 的发展非常快,2 年前的例子是不可行的。


小智 4

我为我的应用程序引用了相同的示例,问题是在 dispose() 期间 AuthStateProvider 没有“取消订阅”。尝试在 State 中实现类似以下内容:

@override
void dispose() {
  var authStateProvider = new AuthStateProvider();
  authStateProvider.unSubscribe(this);
}
Run Code Online (Sandbox Code Playgroud)