【发布时间】:2020-06-05 02:44:48
【问题描述】:
场景:有两个页面。 PhonePage 和 OtpPage 。用户在PhonePage 中输入电话号码并被重定向到OtpPage 以验证发送给他的OTP。
问题:与服务器对话的 API 使用 StreamController.broadcast() 告诉应用程序响应请求。此流由PhonePage 和OtpPage 共享并产生事件。两个页面监听流并根据事件决定做什么。
但是,Navigator.push() 之后,旧页面仍在监听流。因此,当OtpPage 中的用户点击重新发送按钮时,PhonePage 中的Navigator.push 仍会被调用,尽管它不应该调用。
问题 Flutter 必须如何处理这种情况?我试过onDispose(),但它没有被调用。
如果您也能解释为什么也没有调用 onDispose,我将不胜感激。
代码:这是重现场景的代码。您可以将其粘贴到您的 IDE 或 DartPad https://dartpad.dev/flutter (注意:当您转到 OtpPage 并在文本字段中添加一些文本时,单击重新发送按钮。注意如何在顶部添加一个新的 OtpPage 小部件导航树。这是不受欢迎的行为)
import 'dart:async';
import 'package:flutter/material.dart';
final fakeApiResponse = StreamController.broadcast();
void main() => runApp(MyApp(),);
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: PhoneNumber(),
);
}
}
class PhoneNumber extends StatefulWidget {
@override
_PhoneNumberState createState() => _PhoneNumberState();
}
class _PhoneNumberState extends State<PhoneNumber> {
StreamSubscription apiEventListner;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text('Enter your phone number'),
RaisedButton(
child: Text('Send OTP'),
onPressed: () {
fakeApiResponse.add('OTP Sent');
},
),
],
),
);
}
@override
void initState() {
super.initState();
apiEventListner = fakeApiResponse.stream.listen((data) {
if (data == 'OTP Sent') {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => VerifyOtp(),
),
);
}
});
}
@override
void dispose() {
super.dispose();
apiEventListner.cancel();
}
}
class VerifyOtp extends StatefulWidget {
@override
_VerifyOtpState createState() => _VerifyOtpState();
}
class _VerifyOtpState extends State<VerifyOtp> {
StreamSubscription apiEventListner;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
TextField(
decoration: InputDecoration(hintText: 'Enter OTP Here'),
),
RaisedButton(
child: Text("Verify"),
onPressed: () {
fakeApiResponse.add('OTP Verified');
},
),
RaisedButton(
child: Text("Didn't get the code? Resend OTP"),
onPressed: () {
fakeApiResponse.add('OTP Sent');
},
),
],
),
);
}
@override
void initState() {
super.initState();
apiEventListner = fakeApiResponse.stream.listen((data) {
if (data == 'OTP Sent') {
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("OTP Resent"),
content: Text("Enter new OTP"),
);
},
);
}else if (data == 'OTP Verified'){
Navigator.of(context).push(MaterialPageRoute(builder: (context)=>SuccessPage()));
}
});
}
@override
void dispose() {
super.dispose();
apiEventListner.cancel();
}
}
class SuccessPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('SUCCESS!'),
),
);
}
}
【问题讨论】:
-
我无权访问 Api 代码,因为它是一个库,因此我无法控制响应事件名称。 Api 只知道一件事:Send Otp 将响应 Otp Sent。它没有重新发送 Otp 的概念。您只需再次调用 Send Otp 即可重新发送它