wake-up-neo.net

Flutter/Dart Statische Variablen verloren/werden immer wieder neu initialisiert

Ich probiere gerade mit Flutter/Dart aus. Meine statischen Variablen werden jedoch immer wieder neu initialisiert, wenn von einer anderen Klasse aus darauf zugegriffen wird.

Ich habe eine Klasse in ihrer separaten Dart-Quelldatei, die den Serverstatus hält und als solcher deklariert ist:

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

Ich habe sie @ main() von initialisiert

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

. Wenn ich danach versuche, auf einer anderen Seite in meiner Anwendung darauf zuzugreifen, wurden die Variablen 'newestBinary' und 'serverUp' beide zu null, als wären sie wieder reinitalisiert. (Wenn ich sie als static int newestBinary = 10; deklariere, dann ServerStatus.newestBinary = 20; bei main() erneut zuweisen, wird sie immer noch auf einer anderen Seite in meiner Anwendung als 10 angezeigt.

Meine Anwendung wurde zwischen den beiden Vorgängen nicht beendet oder angehalten. Unter welchen Umständen würden statische Variablen wiederbelebt werden? 

Wenn ich globale und häufig verwendete Informationen für die Anwendung vorhalten muss, was wäre der beste Weg, dies zu tun, außer statische Variablen zu verwenden?

Danke im Voraus.

7
Live0

Ich spielte eine Stunde lang herum und erkannte, was der Grund zu sein scheint. Anscheinend, wenn ich tue:

import 'package:flutter_test_app/main.Dart';

Es unterscheidet sich von 

import 'main.Dart';

Auch wenn beide Quelldateien zum selben Paket gehören.

Am Ende sieht mein Testcode also so aus:

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

Der einzige Unterschied ist die Importanweisung. Für pageA/pageB würde die print-Anweisung jedoch "false" angeben. Wie bei pageH würde die print-Anweisung "true" angeben. Ich habe die Import-Anweisungen umgestellt und es wird überprüft. Ich weiß nicht, wie Dart den Code tatsächlich interpretiert. Ich bin mir nicht sicher, ob es sich um eine Dart-Sache, eine Setup-Sache oder ein Flattern-Ding handelt. Ich werde weiter nachforschen, aber jetzt ist mein Problem gelöst.

Danke für die Hilfe aller.

12
Live0

Es scheint, dass Flutter und Dart Probleme haben, dieselbe Instanz für statische (globale) Variable zu finden, wenn der Import mit: "package: your_app_package/file.Dart" beginnt.

Angenommen, Sie möchten eine statische Variable (myStaticVariable) in Ihrer main.Dart-Datei haben, in der sich die MyApp-Klasse befindet. Nehmen wir an, Sie möchten diese statische Variable in einer anderen .Dart-Datei in Ihrem Projekt abrufen, indem Sie sie mit MyApp.myStaticVariable aufrufen. 

Wenn Sie main.Dart mit "import package: your_app_package/main.Dart" importieren, hat die Variable den Wert "null", auch wenn sie zuvor initialisiert wurde!

Wenn Sie main.Dart mit "import main.Dart" importieren (wenn sich die Dateien im selben Verzeichnis befinden) oder "import ../main.Dart" (wenn Ihre Datei ein Verzeichnis ist, dann main.Dart), werden Sie dies tun Holen Sie sich den richtigen Wert für MyApp.myStaticVariable.

Ich bin nicht sicher, warum das so ist, aber wie @Kevin Moore erwähnt, gibt es ein Problem, das das Flutter-Team lösen muss.

5
Sniper

Es ist ein bekanntes Problem, dass die Einstiegsdatei (lib/main.Dart) keine relativen Importe enthalten darf.

Beginnen alle Importe mit 

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

dann kann dieses Problem vermieden werden.

Dies liegt daran, dass Flutter der Pub-Paketkonvention nicht vollständig folgt, wenn Einstiegspunktdateien außerhalb von lib/ liegen (wie bin/, web/, tool/, test/ oder example/).

Siehe auch https://github.com/flutter/flutter/issues/15748

Update 2018-10-17

Dieses Problem wurde in Dart behoben, ist aber möglicherweise noch nicht in allen Flutter-Kanälen gelandet.

2

Sie können statische Variablen direkt in der Deklaration initialisieren. __ Etwas ähnliches wäre besser:

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

Sind Sie sicher, dass Ihre Aufgabe korrekt ausgeführt wird, und vor allem anderen? Ohne mehr Code wäre es schwierig, eine vollständige Antwort zu geben.

Ein anderer Grund könnte sein, wie Sie Ihre Zuweisung erledigen Machen Sie newestBinary = 20; oder ServerStatus.newestBinary = 20;? Wenn Sie newestBinary = 20; tun, ändern Sie nicht die statische Variable von ServerStatus, sondern eine lokale Variable.

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

Verwenden Sie es in einer anderen Datei:

`

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

` Es funktioniert mit import 'glob.Dart';, wenn sich beide Dateien im Verzeichnis lib/befinden. (IDK, wenn in anderen Szenarien Probleme auftreten.)

0
Johan vdH

Der folgende Code verursacht

[FEHLER: flattern/lib/ui/ui_Dart_state.cc (148)] Unbehandelte Ausnahme: Statische Variable '_this @ 69070523' wird während der Initialisierung gelesen

// Singleton Pattern
factory KeyValueService() => _this;
static final KeyValueService _this = new KeyValueService._internal();
KeyValueService._internal();

// Exception .. accessing '_this' during initialization
KeyJsonValue _accountAdapter = new KeyJsonValue(_this, accountKey);

Das Problem ist eine Art 'Race Condition': Während KeyValueService._internal() ausgeführt wird, wird auch accountAdapter initialisiert, was sich auf das noch nicht initialisierte _this Bezieht.

Die Verwendung einer Funktion (=>) anstelle einer Eigenschaft (=) löste das Problem, da new KeyJsonValue(this, …) ausgewertet wird jedes Mal, wenn die Funktion aufgerufen wird und nicht nur einmal) und während der Initialisierung.

KeyJsonValue get _accountAdapter => new KeyJsonValue(this, accountKey);
0
Markus Schmidt

In meiner App musste ich Inhalte aus einer XML-Quelle lesen und in vielen Teilen der App verwenden. Ich wollte den Inhalt einmal laden, als die App gestartet wurde.

Ein statisches Objekt der Klasse BrandsCollection war die perfekte Lösung, aber von einigen Klassen war es null . Ich habe versucht, den Pfad zu ändern, wie die anderen Benutzer dies geschrieben haben, aber es funktioniert trotzdem nicht überall. Deshalb habe ich diese einfache Lösung verwendet:

Mein Hauptbild:

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

In den Klassen, in denen die Instanz gefunden wird, können Sie einfach Folgendes verwenden:

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

        _brandsCollection.foo();
    }
}

Wo es die Instanz irgendwie nicht findet:

Ich habe dieselbe statische Variable erstellt:

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

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

und ich setze die Verbindung zwischen den 2 statischen Variablen in der main:

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

Natürlich müssen Sie den Link vor dem Aufruf der Klasse B erstellen.

0

In meinem Fall liegt das Problem daran, wie ich die Datei importiert habe, die die statische Eigenschaft enthält (import 'package: app/Shared // DIProvider.Dart';). Ich sollte nicht doppelt haben /

0
user3087360