web-dev-qa-db-ja.com

Flutter / Dart静的変数が失われた/再初期化され続ける

今、Flutter/Dartを使って試しています。しかし、私の静的変数は、別のクラスからアクセスされると再初期化され続けます。

そのように宣言されたサーバーステータスを保持するクラスが、別のDartソースファイルにあります。

_class ServerStatus{
  static int newestBinary;
  static bool serverUp;
}
_

@ main()で初期化した

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

。その後、アプリケーションの別のページでそれらにアクセスしようとすると、変数 'newestBinary'と 'serverUp'は両方ともnullになり、再初期化されます。 (_static int newestBinary = 10;_のように宣言し、main()で_ServerStatus.newestBinary = 20;_を再割り当てすると、アプリケーションの別のページで10として表示されます。

2つの操作の間にアプリケーションが終了または停止しませんでした。どのような状況で静的変数が再初期化されますか?

アプリケーションでグローバルで一般的に使用される情報を保持する必要がある場合、静的変数を使用する以外に行う最善の方法は何ですか?

前もって感謝します。

13
Live0

私は1時間いじくり回し、理由のように見えるものを実現しました。どうやら私がするとき:

import 'package:flutter_test_app/main.Dart';

とは違う

import 'main.Dart';

両方のソースファイルが同じパッケージに属している場合でも。

最終的に、私のテストコードは次のようになります。

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

唯一の違いはimportステートメントです。ただし、pageA/pageBの場合、printステートメントは「false」を返します。 pageHの場合、printステートメントは「true」を返します。インポート文を切り替えてチェックアウトしました。 Dartが実際にコードを解釈する方法に慣れていないので、それがDartのものなのか、セットアップのものなのか、フラッターなものなのかわかりません。私は調査を続けますが、今のところ私の問題は解決しました。

みんなの助けてくれてありがとう。

14
Live0

インポートが「package:your_app_package/file.Dart」で始まる場合、FlutterとDartは静的(グローバル)変数の同じインスタンスを見つけるのに問題があるようです。

したがって、main.DartファイルにMyAppクラスがある静的変数(myStaticVariable)が必要だとしましょう。そして、MyApp.myStaticVariableで呼び出すことにより、プロジェクトの別の.Dartファイルでその静的変数を取得したいとしましょう。

その場合、「import package:your_app_package/main.Dart」を指定してmain.Dartをインポートすると、変数は以前に初期化されていても「null」値になります!

「import main.Dart」(ファイルが同じディレクトリにある場合)または「import ../ main.Dart」(ファイルが1つのディレクトリディッパー、次にmain.Dartの場合)だけでmain.Dartをインポートすると、 MyApp.myStaticVariableの正しい値を取得します。

なぜだかわかりませんが、@ Kevin Mooreが言ったように、問題があり、Flutterチームはそれを解決する必要があります。

9
Sniper

エントリポイントファイル(lib/main.Dart)に相対インポートが含まれてはならないことは既知の問題です。

すべてのインポートが次で始まる場合

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

この問題は回避できます。

これは、Flutterは、エントリポイントファイルがlib/bin/web/tool/test/などの外部にあるpubパッケージの規則に完全に従っていないためです。 、またはexample/)。

こちらもご覧ください https://github.com/flutter/flutter/issues/15748

2018年10月17日更新

この問題はDartで修正されていますが、すべてのFlutterチャンネルにまだ上陸していない可能性があります。

3

静的変数を宣言で直接初期化できます。このような何かが良いでしょう:

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

また、割り当てが正しく実行され、他の何よりも先に実行されますか?コードを追加しなければ、完全な答えを出すのは非常に困難です。

もう1つの理由は、割り当ての方法に関するものです。あなたはnewestBinary = 20;またはServerStatus.newestBinary = 20;?静的変数はグローバル変数とは異なります。もしあなたがそうするなら newestBinary = 20; ServerStatusの静的変数は変更せず、代わりにローカル変数を変更します。

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

別のファイルで使用します:

`

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

`import 'glob.Dart';両方のファイルがlib /ディレクトリにある場合。 (他のシナリオに問題がある場合はIDK。)

1
Johan vdH

次のコードにより

[ERROR:flutter/lib/ui/ui_Dart_state.cc(148)]未処理の例外:初期化中に静的変数 '_this @ 69070523'を読み取ります

_// 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);
_

問題はある種の「競合状態」です:KeyValueService._internal()の実行中に、accountAdapterも初期化されますが、それ自体はまだ初期化されていない__this_を参照します。

プロパティ(=)の代わりに関数(=>)を使用すると、new KeyJsonValue(this, …)が評価されるため、問題が解決しました関数が呼び出されるたびにおよび1回だけではありません)および初期化中

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

私のアプリでは、xmlソースからコンテンツを読み取り、アプリの多くの部分で使用する必要がありました。アプリの起動時にコンテンツを一度ロードしたかった。

クラスBrandsCollectionの静的オブジェクトは完璧な解決策でしたが、一部のクラスではnullでした。他のユーザーが書いたようにパスを変更しようとしましたが、それでもどこでも機能しませんでしたので、この簡単な解決策を使用しました:

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

インスタンスを見つけるクラスでは、単に使用できます:

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

        _brandsCollection.foo();
    }
}

どういうわけかインスタンスが見つからない場合:

同じ静的変数を作成しました:

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

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

メインの2つの静的変数間のリンクを設定します。

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

もちろん、クラスBを呼び出す前にリンクを作成する必要があります。

0

私の場合、問題は静的プロパティを含むファイルをインポートした方法に由来します(import 'package:app/Shared // DIProvider.Dart';)。私は二重にすべきではありません/

0
user3087360