Синглтон во Flutter выдает ошибку времени выполнения «Необработанное исключение: чтение данных c переменная '_instance@545324594' во время инициализации» - PullRequest
0 голосов
/ 18 марта 2020

Я пытался реализовать MVP-Pattern в приложении Flutter (Flutter версия 1.12.13 + hotfix8). Мой контроллер (докладчик) является одноэлементным и выглядит так:

import 'package:flutter/material.dart';

// local file imports
import 'package:prototype/gui/screens/welcome/welcome.dart';

// this is a singleton
class Controller  {
  static final Controller _instance = Controller._internal();
  Widget _currentWidget;

  Controller._internal() {
    this._currentWidget = ScreenWelcome();
  }

  factory Controller() => _instance;

  Widget get currentWidget => this._currentWidget;

  set currentWidget(Widget widget){
    _currentWidget = widget;
  }
}

Мой домашний экран выглядит так:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

// local file imports
import 'package:prototype/controller/conroller.dart';
import 'package:prototype/gui/screens/register/register.dart';
import 'package:prototype/gui/screens/register/sign_in.dart';
import 'package:prototype/gui/screens/text_viewer/text_viewer.dart';

class ScreenWelcome extends StatelessWidget {
  final _controller = Controller();

  @override
  Widget build(BuildContext context) {
    return Container(
      child: SingleChildScrollView(
        child: Column(
          children: <Widget>[
            Image.asset('resources/zombiepaar.jpg',
                width: 500, height: 500, fit: BoxFit.fitWidth),
            SizedBox(
              height: 20.0,
            ),
            RaisedButton(
              child: Text("Ein neues Konto erstellen"),
              onPressed: () => _controller.currentWidget = ScreenRegister(),
            ),
            SizedBox(
              height: 20.0,
            ),
            RaisedButton(
              child: Text("Mit bestehendem Konto einloggen"),
              onPressed: () => _controller.currentWidget = ScreenSignIn(),
            ),
            SizedBox(
              height: 20.0,
            ),
            Row(
              children: <Widget>[
                GestureDetector(
                  child: Text(
                    "Nutzungsbedingungen",
                    style: TextStyle(
                        decoration: TextDecoration.underline,
                        color: Colors.blue),
                  ),
                  onTap: () => Navigator.push(
                      context,
                      MaterialPageRoute(
                        builder: (context) => ScreenTextViewer(
                            title: "Nutzungsbedingungen",
                            ressourceFileToLoad: 'resources/AGBs.txt'),
                      )),
                ),
                SizedBox(
                  width: 20.0,
                ),
                GestureDetector(
                  child: Text(
                    "Datenschutzrichtlinien",
                    style: TextStyle(
                        decoration: TextDecoration.underline,
                        color: Colors.blue),
                  ),
                  onTap: () => Navigator.push(
                    context,
                    MaterialPageRoute(
                      builder: (context) => ScreenTextViewer(
                          title: "Nutzungsbedingungen",
                          ressourceFileToLoad: 'resources/AGBs.txt'),
                    ),
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

Но когда я запускаю свое приложение, я получаю следующую ошибку времени выполнения:

D/FlutterActivityAndFragmentDelegate(21372): Executing Dart entrypoint: main, and sending initial route: /
E/flutter (21372): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: Reading static variable '_instance@545324594' during its initialization
E/flutter (21372): #0      Controller._instance (package:prototype/controller/conroller.dart:9:27)
E/flutter (21372): #1      new Controller (package:prototype/controller/conroller.dart:17:27)
E/flutter (21372): #2      new ScreenWelcome (package:prototype/gui/screens/welcome/welcome.dart:11:23)
E/flutter (21372): #3      new Controller._internal (package:prototype/controller/conroller.dart:14:27)
E/flutter (21372): #4      Controller._instance (package:prototype/controller/conroller.dart:9:50)
E/flutter (21372): #5      Controller._instance (package:prototype/controller/conroller.dart:9:27)
E/flutter (21372): #6      new Controller (package:prototype/controller/conroller.dart:17:27)
E/flutter (21372): #7      new MyApp (package:prototype/main.dart:10:22)
E/flutter (21372): #8      main (package:prototype/main.dart:6:23)
E/flutter (21372): #9      _runMainZoned.<anonymous closure>.<anonymous closure> (dart:ui/hooks.dart:239:25)
E/flutter (21372): #10     _rootRun (dart:async/zone.dart:1126:13)
E/flutter (21372): #11     _CustomZone.run (dart:async/zone.dart:1023:19)
E/flutter (21372): #12     _runZoned (dart:async/zone.dart:1518:10)
E/flutter (21372): #13     runZoned (dart:async/zone.dart:1502:12)
E/flutter (21372): #14     _runMainZoned.<anonymous closure> (dart:ui/hooks.dart:231:5)
E/flutter (21372): #15     _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:307:19)
E/flutter (21372): #16     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:174:12)

Есть идеи, как это исправить? Я не нашел ничего полезного с Google, и я довольно новичок в дартс и флаттер. Может быть, я реализовал синглтон-класс неправильно?

Редактировать: Mi main.dart file is

import 'package:flutter/material.dart';

// local file imports
import 'package:prototype/controller/conroller.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of the application.
  final controller = Controller(); // presenter in MVP design pattern

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'MyApp',
      home: controller.currentWidget, // controller decides the main widget
    );
  }
}


Ответы [ 2 ]

0 голосов
/ 19 марта 2020

У вас есть циклическая c зависимость. Создание ScreenWelcome вызывает конструктор Controller, который читает поле _instance, которое создает Controller, которое создает ScreenWelcome. Вам повезло, что поле _instance лениво, потому что тогда оно обнаруживает цикл раньше, а не переполняет стек.

Если у вас есть два класса с конечными полями, которые должны указывать друг на друга. Это в принципе невозможно. К счастью, _currentWidget не является окончательным, поэтому его нужно установить после создания обоих объектов.

Я бы сделал что-то вроде:

class Controller {
  static final _instance = Controller._();
  Widget_currentWidget;
  factory Controller() => _instance;
  Controller._();
}
class ScreenWelcome {
  final Controller _controller;
  ScreenWelcome() : _controller = Controller() {
    // This is the soonest a reference to this widget is available.
    _controller.currentWidget = this; 
  }
}
0 голосов
/ 18 марта 2020

Наконец-то я нашел ответ: я должен вызвать конструктор виджета как можно позже. Поэтому я вызвал его в функции получения. Рабочий код выглядит так:

import 'package:flutter/material.dart';

// local file imports
import 'package:prototype/gui/screens/welcome/welcome.dart';

// this is a singleton
class Controller  {
  static final Controller _instance = Controller._internal();
  Function _currentWidget;

  Controller._internal() {
    this._currentWidget = () => ScreenWelcome();
  }

  factory Controller() => _instance;

  Widget get currentWidget => this._currentWidget();

  set currentWidget(Widget widget){
    _currentWidget = () => widget;
  }
}

Может быть, однажды это кому-нибудь поможет:)

...