I am trying out things with Flutter/Dart right now. But my static variables keep getting reinitialised when accessed from another class.
I have a class, in its separate dart source file, holding the server status, declared as such:
class ServerStatus{
static int newestBinary;
static bool serverUp;
}
I initialised them @ main()
by
ServerStatus.newestBinary = 20;
ServerStatus.serverUp = true;
. Afterwards, when I try to access them at another page in my application, the variables 'newestBinary
' and 'serverUp
' both became null
, as if they are reinitalised. (If I declare them like static int newestBinary = 10;
, then reassign ServerStatus.newestBinary = 20;
at main()
, it would still show up as 10 at another page in my application.
My application did not quit or stop between the two operations. Under what circumstances would static variables be reinitalised?
If I have to hold global and commonly used information for the application, what would be the best way to do it other than using static variables?
Thanks in advance.
I toyed around for an hour and realise what appears to be the reason. Apparently when I do:
import 'package:flutter_test_app/main.dart';
It is different from
import 'main.dart';
Even if both source files belong to the same package.
So in the end my test code looks like:
main.dart:
import 'package:flutter/material.dart';
import 'pageA.dart';
import 'pageB.dart';
import 'pageH.dart';
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
static bool testFlag = false;
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
testFlag = true;
ThemeData mainTheme = new ThemeData(
primarySwatch: Colors.cyan,
);
print("testFlag @ MyApp: " + testFlag.toString());
MaterialApp mainApp = new MaterialApp(
title: 'Instabazaar',
theme: mainTheme,
home: new HomePage(title: 'Instabazaar'),
);
return mainApp;
}
}
class HomePage extends StatefulWidget {
final String title;
HomePage({Key key, this.title}) : super(key: key);
@override
_HomePageState createState() {
return new _HomePageState();
}
}
class _HomePageState extends State<HomePage> {
int _currentPageID = 0; // 0=home, 1=pageA, 2=pageB
@override
Widget build(BuildContext context) {
print("testFlag @ HomePage: " + MyApp.testFlag.toString());
AppBar appBar = new AppBar(
title: new Text("TestApp"),
centerTitle: true,
);
BottomNavigationBar bottomNavigationBar = new BottomNavigationBar(
type: BottomNavigationBarType.shifting,
items: <BottomNavigationBarItem>[
new BottomNavigationBarItem(icon: new Icon(Icons.home), title: new Text('Home'), backgroundColor: Theme.of(context).accentColor),
new BottomNavigationBarItem(icon: new Icon(Icons.explore), title: new Text('PageA'), backgroundColor: Colors.purple),
new BottomNavigationBarItem(icon: new Icon(Icons.star), title: new Text('PageB'), backgroundColor: Colors.redAccent),
],
onTap: (i) => setState( () => _currentPageID = i ),
currentIndex: _currentPageID
);
Scaffold mainScaffold = new Scaffold(
appBar: appBar,
body: _getNewSubPage(),
bottomNavigationBar: bottomNavigationBar,
);
return mainScaffold;
}
//MARK: navigation
Widget _getNewSubPage(){
switch (_currentPageID)
{
case 1:
return new pageA();
case 2:
return new pageB();
default:
return new pageH();
}
}
}
pageA.dart / pageB.dart:
import 'package:flutter/material.dart';
import 'package:flutter_test_app/main.dart';
class pageA extends StatefulWidget{
pageAState createState() => new pageAState();
}
class pageAState extends State<pageA> {
@override
Widget build(BuildContext context) {
print("testFlag @ pageA: " + MyApp.testFlag.toString());
return new Container();
}
}
pageH.dart:
import 'package:flutter/material.dart';
import 'main.dart';
class pageH extends StatefulWidget{
pageHState createState() => new pageHState();
}
class pageHState extends State<pageH> {
@override
Widget build(BuildContext context) {
print("testFlag @ pageH: " + MyApp.testFlag.toString());
return new Container();
}
}
The only difference is the import statement. However, for pageA/pageB, the print statement would give "false". As for pageH, the print statement would give "true". I have switched around the import statements and it checks out. I am not familiar with how dart actually interprets the code, so I am not sure if it is a dart thing, a setup thing or a flutter thing. I will continue investigating but for now my problem is solved.
Thanks for everyone's help.
It seems that Flutter and Dart have issue to find the same instance for static (global) variable if the import starts with: "package:your_app_package/file.dart".
So let say you want to have static variable (myStaticVariable) in your main.dart file, where you have MyApp class. And let say that you want to get that static variable in some different .dart file in your project, by calling it with MyApp.myStaticVariable.
In that case if you import main.dart with "import package:your_app_package/main.dart" the variable will have "null" value , even if it has been initialised before!
If you import main.dart with just "import main.dart" (if the files are in the same directory) or "import ../main.dart" (if your file is one directory dipper then main.dart), you will get the right value for MyApp.myStaticVariable.
I am not sure why is that, but maybe like @Kevin Moore mentioned, there is an issue and Flutter team needs to resolve it.
class Glob {
//One instance, needs factory
static Glob _instance;
factory Glob() => _instance ??= new Glob._();
Glob._();
//
String account ='johanacct1';
String getServerUrl(){
return 'http://192.168.1.60';
}
String getAccountUrl(){
return getServerUrl()+'/accounts/'+account;
}
}
Use it in another file:
`
Glob().getAccountUrl(); //http://192.168.1.60/accounts/johanacct1
Glob().account = 'philip.k.dick';
Glob().getAccountUrl(); //http://192.168.1.60/accounts/philip.k.dick
`
It works with import 'glob.dart';
when both files are in the lib/ directory. (IDK if there are problems in other scenarios.)
It's a known issue that the entry-point file (lib/main.dart
) must not contain relative imports.
If all imports start with
import 'dart:...';
import 'package:my_project/...'
then this problem can be avoided.
This is because Flutter doesn't fully follow the pub package convention where entry-point files are outside lib/
(like bin/
, web/
, tool/
, test/
, or example/
).
See also https://github.com/flutter/flutter/issues/15748
Update 2018-10-17
This issue is fixed in Dart but might not have landed yet in all Flutter channels.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With