Whenever I click Run Query button I get the expected result in the terminal but I have to click it once again to be able to display the result in the UI!
I guess there is something wrong in setState
usage. May you please help me to find out what's wrong?
PS. I tried to use both suggested cases of setState
mentioned in this post but I always get the same result.
import 'package:flutter/material.dart';
import 'package:mysql1/mysql1.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'MySQL Test',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'MySQL Test'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String? _barcode;
late bool visible;
@override
var Connection;
String? res;
void initsql() async {
try {
var settings = ConnectionSettings(
host: '127.0.0.1',
port: 3306,
user: 'root',
db: 'testo',
password: '1234',
timeout: Duration(minutes: 2));
Connection = await MySqlConnection.connect(settings);
print("Connected");
} catch (e) {
print(e);
}
}
void getResult() async {
var results = await Connection.query('SELECT id, Name FROM testo.mytable');
for (var row in results) {
res = 'ID: ${row[0]}, Name: ${row[1]}'; //---> Needs Double click!
print('ID: ${row[0]}, Name: ${row[1]}');
}
}
void initState() {
initsql();
super.initState();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
res == null ? 'Disconnected!' : '$res',
style: Theme.of(context).textTheme.headline5,
),
Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
children: [
ElevatedButton(
onPressed: () => setState(() {
//---> Needs Double click!!
getResult();
}),
child: Center(child: Text('Run Query'))),
],
),
)
],
),
),
);
}
}
CodePudding user response:
First of all your getResult
method is asynchronous, so the return type is not void
but Future<void>
.
Future<void> getResult() async {
var results = await Connection.query('SELECT id, Name FROM testo.mytable');
for (var row in results) {
res = 'ID: ${row[0]}, Name: ${row[1]}'; //---> Needs Double click!
print('ID: ${row[0]}, Name: ${row[1]}');
}
}
The reason why you UI doesn't update the widget on your first tap is, that your getResult
is asynchronous. In your button you call setState
, which triggers a rebuild of your widget, but since the method is asynchronous, it cannot provide a result immediately when it is started. This means you call setState
, it updates your UI, then your method retrieves the new value of getResult
, but the UI got updated before that. To fix this you have to wait for your method until it has finished and then call setState
to update your UI.
ElevatedButton(
onPressed: () async {
await getResult();
setState((){});
} ,
child: Center(
child: Text('Run Query'),
),
);