web-dev-qa-db-fra.com

Flutter/Dart Variables statiques perdues/réinitialisées

J'essaie des choses avec Flutter/Dart en ce moment. Mais mes variables statiques continuent à se réinitialiser lorsqu’elles sont utilisées depuis une autre classe.

J'ai une classe, dans son fichier source Dart séparé, contenant le statut du serveur, déclarée comme telle:

class ServerStatus{
  static int newestBinary;
  static bool serverUp;
}

Je les ai initialisé @ main() par

ServerStatus.newestBinary = 20;
ServerStatus.serverUp = true;

. Ensuite, lorsque j'essaie d'y accéder sur une autre page de mon application, les variables 'newestBinary' et 'serverUp' sont toutes les deux devenues null, comme si elles étaient réinitalisées. (Si je les déclare comme static int newestBinary = 10;, puis réaffectez ServerStatus.newestBinary = 20; à main(), il apparaîtra toujours sous la forme 10 sur une autre page de mon application.

Ma demande n'a pas été abandonnée ni arrêtée entre les deux opérations. Dans quelles circonstances les variables statiques seraient-elles ré-initialisées? 

Si je dois conserver des informations globales et couramment utilisées pour l'application, quel serait le meilleur moyen de le faire, si ce n'est d'utiliser des variables statiques?

Merci d'avance.

7
Live0

J'ai joué pendant une heure et je me suis rendu compte de ce qui semblait être la raison. Apparemment quand je fais:

import 'package:flutter_test_app/main.Dart';

C'est différent de 

import 'main.Dart';

Même si les deux fichiers source appartiennent au même package.

En fin de compte, mon code de test ressemble à ceci:

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();
  }
}

La seule différence est la déclaration d'importation. Cependant, pour pageA/pageB, la déclaration print donnerait "false". En ce qui concerne pageH, la déclaration print donnerait la valeur "true". J'ai inversé les instructions d'importation et le résultat est vérifié. Je ne suis pas au courant de la façon dont Dart interprète le code. Je ne suis donc pas sûr que ce soit un problème de Dart, de configuration ou de scintillement. Je vais continuer à enquêter mais pour l'instant mon problème est résolu.

Merci pour l'aide de tous.

12
Live0

Il semble que Flutter et Dart ne rencontrent pas le même problème pour trouver la même instance pour une variable statique (globale) si l'importation commence par: "package: votre_app_package/fichier.Dart".

Supposons donc que vous souhaitiez avoir une variable statique (myStaticVariable) dans votre fichier main.Dart, où vous avez la classe MyApp. Et disons que vous voulez obtenir cette variable statique dans un fichier .Dart différent de votre projet, en l'appelant avec MyApp.myStaticVariable. 

Dans ce cas, si vous importez main.Dart avec "package d'importation: your_app_package/main.Dart", la variable aura la valeur "null", même si elle a été initialisée auparavant!

Si vous importez main.Dart uniquement avec "import main.Dart" (si les fichiers se trouvent dans le même répertoire) ou "import ../main.Dart" (si votre fichier est un répertoire dipper puis main.Dart), vous Obtenez la bonne valeur pour MyApp.myStaticVariable.

Je ne sais pas trop pourquoi, mais peut-être que @Kevin Moore l'a mentionné, il existe un problème et l'équipe de Flutter doit le résoudre.

5
Sniper

On sait que le fichier de point d'entrée (lib/main.Dart) ne doit pas contenir d'importations relatives.

Si toutes les importations commencent par 

import 'Dart:...';
import 'package:my_project/...'

alors ce problème peut être évité.

Cela est dû au fait que Flutter ne respecte pas totalement la convention de paquetage pub selon laquelle les fichiers de point d’entrée sont en dehors de lib/ (comme bin/, web/, tool/, test/ ou example/).

Voir aussi https://github.com/flutter/flutter/issues/15748

Mise à jour 2018-10-17

Ce problème est résolu dans Dart mais n’a peut-être pas encore atterri dans tous les canaux Flutter.

2

Vous pouvez initialiser une variable statique directement dans la déclaration . Quelque chose comme cela serait mieux:

class ServerStatus{
  static int newestBinary = 20;
  static bool serverUp = false;
}

Aussi, êtes-vous sûr que votre assignation est correctement exécutée et avant toute chose? Sans plus de code, il serait très difficile de donner une réponse complète.

Une autre raison peut être liée à la façon dont vous effectuez votre affectation . Faites-vous newestBinary = 20; ou ServerStatus.newestBinary = 20;? Si vous faites newestBinary = 20;, vous ne modifierez pas la variable statique de ServerStatus, mais une variable locale.

1
Rémi Rousselet
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;
  }
}

Utilisez-le dans un autre fichier:

`

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

` Il fonctionne avec import 'glob.Dart'; lorsque les deux fichiers sont dans le répertoire lib /. (IDK s'il y a des problèmes dans d'autres scénarios.)

0
Johan vdH

Dans mon application, je devais lire le contenu d'une source XML et l'utiliser dans de nombreuses parties de l'application. Je voulais charger le contenu une fois, lorsque l'application a démarré.

Un objet statique de la classe BrandsCollection était la solution parfaite, mais pour certaines classes, il était null .. J'ai essayé de modifier le chemin comme les autres utilisateurs l'avaient écrit, mais cela ne fonctionnait toujours pas.

Mon Main.Dart:

class GlobalData {
  //this is what I need to have in many parts of my app
  static BrandsCollection brandsCollection;
}

void main() {
  XmlDataReader dataReader = new XmlDataReader();

  dataReader.loadContent().then((content) {
      //After reading the xml file, I create the instance
      GlobalData.brandsCollection = new BrandsCollection(content);

      //I run the app only when the object is initialized
      runApp(new MyApp());
  });
}

Dans les classes où il trouve l'instance, vous pouvez simplement utiliser:

import '../main.Dart';
class A {
    A(){
        BrandsCollection _brandsCollection = GlobalData.brandsCollection;

        _brandsCollection.foo();
    }
}

Où il ne trouve pas l'instance:

J'ai créé la même variable statique:

import '../main.Dart';
class B {
    //This is gonna be the copy of the value
    static BrandsCollection brandsCollection;

    B(){
        brandsCollection.foo();
    }
}

et je fixe le lien entre les 2 variables statiques dans la principale:

void main() {
  XmlDataReader dataReader = new XmlDataReader();

  dataReader.loadContent().then((content) {
      GlobalData.brandsCollection = new BrandsCollection(content);

      //This is the link
      B.brandsCollection = GlobalData.brandsCollection;

      runApp(new MyApp());
  });
}

Bien sûr, vous devez créer le lien avant l'appel de classe B.

0