Я хотел бы, чтобы виджет на экране как можно быстрее, когда мое приложение запускается. После того, как виджет был показан пользователю, я хотел бы выполнить некоторую инициализацию приложения (например, настроить базу данных), прежде чем покинуть экран запуска, нажав другой экран. Я не могу понять, куда поместить код инициализации моего приложения. Нечто аналогичное viewDidAppear в iOS.

Это то, что я пытался на основе initState.

class Launch extends StatefulWidget {
  @override
  _LaunchState createState() {
    return _LaunchState();
  }
}

class _LaunchState extends State<Launch> {
  @override
  Widget build(final BuildContext context) {
    print('LaunchState build start');
    final Widget w = Center(
      child: Text('Launching...'),
    );
    print('LaunchState build end');
    return w;
  }

  @override
  void initState() {
    print('LaunchState initState start');
    super.initState();
    print('LaunchState initState middle');
    _appInitialization();
    print('LaunchState initState end');
  }

  void _appInitialization() {
    print('LaunchState _appInitialization');
  }

}

Результат был

flutter: LaunchState initState start
flutter: LaunchState initState middle
flutter: LaunchState _appInitialization
flutter: LaunchState initState end
flutter: LaunchState build start
flutter: LaunchState build end

Вывод, который я хочу увидеть, это

flutter: LaunchState build start
flutter: LaunchState build end
flutter: LaunchState initState start
flutter: LaunchState initState middle
flutter: LaunchState _appInitialization
flutter: LaunchState initState end

Может быть, я собираюсь об этом совершенно беззаботно. Если есть совершенно другой подход, я все уши.

РЕШЕНИЕ

Благодаря ответу Мангалдипа Панну кажется, что я скучаю async.

class Launch extends StatefulWidget {
  @override
  _LaunchState createState() {
    return _LaunchState();
  }
}

class _LaunchState extends State<Launch> {
  @override
  Widget build(final BuildContext context) {
    print('LaunchState build start');
    final Widget w = Center(
      child: Text('Launching...'),
    );
    print('LaunchState build end');
    return w;
  }

  @override
  void initState() {
    print('LaunchState initState start');
    super.initState();
    print('LaunchState initState middle');
    _appInitialization(); // no await
    print('LaunchState initState end');
  }

  void _appInitialization() async {
    print('LaunchState _appInitialization begin');
    // simulate some time consuming initialization task
    await Future.delayed(Duration(seconds: 5));
    print('LaunchState _appInitialization middle');
    Navigator.push(...);
    print('LaunchState _appInitialization end');
  }

}

Результаты

flutter: LaunchState initState start
flutter: LaunchState initState middle
flutter: LaunchState _appInitialization begin
flutter: LaunchState initState end
flutter: LaunchState build start
flutter: LaunchState build end
[5 second pause]
flutter: LaunchState _appInitialization middle
flutter: LaunchState _appInitialization end
8
Ted Henry 14 Апр 2019 в 06:20

2 ответа

Лучший ответ

В вашем первом виджете, который открывается при запуске приложения

@override
void initState() {
  onStart();
}

void onStart() async {
  await loadData();  //load your data here
  Navigator.push();  //push to next screen
}

onStart загрузит данные асинхронно .
И когда данные загружаются, нажмите на следующий экран.

3
Mangaldeep Pannu 14 Апр 2019 в 13:12

Ну, мы можем справиться с этим с BLoC.

Создайте файл app_bloc.dart и AppBloc class, как показано ниже:

import 'dart:async';

final appBloc =  AppBloc();

enum AppEvent{
  onStart, onAppInitialized, onStop
}

class AppBloc {
  final _appEventController = StreamController<AppEvent>.broadcast();

  Stream<AppEvent> get appEventsStream => _appEventController.stream;

  dispatch(AppEvent event) {
    switch(event) {
      case AppEvent.onStart:
        _initializeApp();
        _sinkEvent(AppEvent.onStart);
        break;
      case AppEvent.onStop:
        _dispose();
        _sinkEvent(AppEvent.onStop);
        break;
      case AppEvent.onAppInitialized:
        _sinkEvent(AppEvent.onAppInitialized);
        break;
    }
  }

  void _sinkEvent(AppEvent appEvent) => _appEventController.sink.add(appEvent);

  _dispose() {
    _appEventController.close();
  }

  void _initializeApp() async {
    await DBProvider.db.initDB();
    dispatch(AppEvent.onAppInitialized); // will execute when all initializations are complete,
  }
}

Создайте файл database.dart и вставьте в него DBProvider class:

class DBProvider {
  static final DBProvider _instance = new DBProvider._internal();

  static final db = DBProvider();

  factory DBProvider() {
    return _instance;
  }

  DBProvider._internal();

  initDB() async {
    // todo initialize your database here.
  }
}

Ваш основной файл должен быть примерно таким:

import 'package:flutter/material.dart';

import 'package:st_overflow/app_bloc.dart';

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

class App extends StatefulWidget {

  App() {
    appBloc.dispatch(AppEvent.onStart);
  }

  @override
  _AppState createState() => _AppState();
}

class _AppState extends State<App> {

  @override
  Widget build(BuildContext context) {
    return Launch();
  }

  @override
  void dispose() {
    appBloc.dispatch(AppEvent.onStop);
    super.dispose();
  }
}

И в вашем Launch Widget используйте событие onAppInitialize, используя StreamBuilder, например:

StreamBuilder(
    stream: appBloc.appEventsStream,
    builder: (context, snapshot){
        switch (snapshot.data) {
            case AppEvent.onAppInitialized:
            // remove your Launch widget and show Screen 1 of your app (may be dashboard or something).
            break;        
        }
    },
);
1
Kalpesh Kundanani 14 Апр 2019 в 08:14