Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter/Dart Static variables lost / keep getting reinitialized

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.

like image 640
Live0 Avatar asked Aug 19 '17 13:08

Live0


4 Answers

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.

like image 72
Live0 Avatar answered Oct 22 '22 01:10

Live0


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.

like image 33
Stoycho Andreev Avatar answered Oct 22 '22 03:10

Stoycho Andreev


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.)

like image 15
Johan vdH Avatar answered Oct 22 '22 03:10

Johan vdH


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.

like image 7
Günter Zöchbauer Avatar answered Oct 22 '22 03:10

Günter Zöchbauer