Probably it's my fault or a dumb error but this is what is happening to me:
authController.dart:
class AuthController {
BehaviorSubject _hometownController = BehaviorSubject();
Observable get hometown => _hometownController.stream;
void updateHometown(String hometown) {
_hometownController.add(hometown);
print(_hometownController.value); <- This always prints the expected value: "Hello!"`
}
}
Login_screen.dart:
class Login2 extends StatelessWidget {
AuthController authController = new AuthController();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Builder(
builder: (BuildContext context) =>
Container(
padding: EdgeInsets.all(32.0),
child: Center(
child:
//Hometown:
StreamBuilder(
stream: authController.hometown,
builder: (BuildContext context, AsyncSnapshot snap) {
return ListTile(
leading: Icon(Icons.map),
title: Text("Hometown:"),
subtitle: snap.hasData ? Text(snap.data) : Text("Not set"),
onTap: () {
authController.updateHometown("Hello!");
},
);
}
),
))));}}
And everything goes well. But if I add an asynchronous function with async and await before authController.updateHometown:
Login_screen.dart:
onTap: () async {
var x = await something(); <- This always successfully completes
authController.updateHometown("Hello!");
},
The stream never receives the new value and the StreamBuilder never rebuilds!
But if I use a statefulWidget class:
class Login2 extends StatefulWidget {
@override
State<StatefulWidget> createState() => Login2State();
}
class Login2State extends State<Login2> {
AuthController authController;
@override
void initState() {
authController = new AuthController();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Builder(
builder: (BuildContext context) =>
Container(
padding: EdgeInsets.all(32.0),
child: Center(
child:
//Hometown:
StreamBuilder(
stream: authController.hometown,
builder: (BuildContext context, AsyncSnapshot snap) {
return ListTile(
leading: Icon(Icons.map),
title: Text("Hometown:"),
subtitle: snap.hasData ? Text(snap.data) : Text("Not set"),
onTap: () async {
var x = await something();
authController.updateHometown("Hello!");
},
);
}),))));}}
Everything goes well, even if I never call setState Why is this happening?
From Framework.dart
:
A StatelessWidget
builds itself depending on data that has two conditions:
That's why when you make Login2
as StatelessWidget
, and then change the data in authController
synchronously it is immediately reflected because it satisfies both conditions. But when you use an async
function inside onTap()
you break the first one.
And why StatefulWidget
works with async
function is because its build
function only needs a data change to trigger setState()
implicitly irrespective of whether this info is available synchronously or asynchronously.