如何在Flutter中更改运行时的应用主题?

时间:2018-11-19 17:26:13

标签: dart flutter

在我的简单项目中,有一个按钮可以将主题形式的浅色更改为深色,反之亦然,如下所示:

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:async';

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

class MyApp extends StatefulWidget {
  @override
  MyAppState createState() {
    return new MyAppState();
  }
}

class MyAppState extends State<MyApp> {
  Future<bool> load(String key, bool defaultValue) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    bool state = prefs.getBool(key) ?? defaultValue;
    return state;
  }

  Future<void> save(String key, bool value) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    prefs.setBool(key, value);
  }

  bool state;

  @override
  Widget build(BuildContext context) {
    load("themeKey", false).then((bool value) {
      state = value;
    });
    debugPrint(
        "..............state is : " + state.toString() + "...............");
    return MaterialApp(
      theme: state ? ThemeData.light() : ThemeData.dark(),
      home: Scaffold(
        body: Container(
          child: RaisedButton(
            child: Text("change"),
            onPressed: () {
              setState(() {
                state = !state;
              });
              save("themeKey", state);
            },
          ),
        ),
      ),
    );
  }
}

我使用shared_preferences插件保存了下次启动应用程序时的当前主题状态,但是有一个问题,似乎是应用程序在共享首选项加载之前就已加载,因此我得到了这个 exception

Launching lib\main.dart on C1905 in debug mode...
Built build\app\outputs\apk\debug\app-debug.apk.
I/flutter ( 8045): ..............state is : null...............
I/flutter ( 8045): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 8045): The following assertion was thrown building MyApp(dirty, state: MyAppState#6774f):
I/flutter ( 8045): Failed assertion: boolean expression must not be null
I/flutter ( 8045): Either the assertion indicates an error in the framework itself, or we should provide substantially
I/flutter ( 8045): more information in this error message to help you determine and fix the underlying cause.
I/flutter ( 8045): In either case, please report this assertion by filing a bug on GitHub:
I/flutter ( 8045):   https://github.com/flutter/flutter/issues/new?template=BUG.md
I/flutter ( 8045): When the exception was thrown, this was the stack:
I/flutter ( 8045): #0      MyAppState.build (package:test_shared_preferenced/main.dart:36:14)
I/flutter ( 8045): #1      StatefulElement.build (package:flutter/src/widgets/framework.dart:3787:27)
I/flutter ( 8045): #2      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3699:15)
I/flutter ( 8045): #3      Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
I/flutter ( 8045): #4      ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3679:5)
I/flutter ( 8045): #5      StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3826:11)
I/flutter ( 8045): #6      ComponentElement.mount (package:flutter/src/widgets/framework.dart:3674:5)
I/flutter ( 8045): #7      Element.inflateWidget (package:flutter/src/widgets/framework.dart:2950:14)
I/flutter ( 8045): #8      Element.updateChild (package:flutter/src/widgets/framework.dart:2753:12)
I/flutter ( 8045): #9      RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:909:16)
I/flutter ( 8045): #10     RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:880:5)
I/flutter ( 8045): #11     RenderObjectToWidgetAdapter.attachToRenderTree.<anonymous closure> (package:flutter/src/widgets/binding.dart:826:17)
I/flutter ( 8045): #12     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2266:19)
I/flutter ( 8045): #13     RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:825:13)
I/flutter ( 8045): #14     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding&WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:712:7)
I/flutter ( 8045): #15     runApp (package:flutter/src/widgets/binding.dart:756:7)
I/flutter ( 8045): #16     main (package:test_shared_preferenced/main.dart:5:16)
I/flutter ( 8045): #17     _startIsolate.<anonymous closure> (dart:isolate/runtime/libisolate_patch.dart:289:19)
I/flutter ( 8045): #18     _RawReceivePortImpl._handleMessage (dart:isolate/runtime/libisolate_patch.dart:171:12)
I/flutter ( 8045): ════════════════════════════════════════════════════════════════════════════════════════════════════

在这种情况下我该怎么办,请帮忙

1 个答案:

答案 0 :(得分:1)

load方法返回一个Future,它将与其余代码异步运行。当执行到达debugPrint或后续的return语句时,不能保证then块已完成其执行。您收到的错误证实了这一点。 state布尔值尚未设置为一个值-它仍然为空。

使用FutureBuilder可以帮助您处理正在等待Future来构建窗口小部件树的情况。

https://www.dartlang.org/tutorials/language/futures值得一读。