

モデル内でShared Preferencesを用いて、データを保存したいのですがうまくいきません。  
例えば、下の例は、デフォルトのカウントアップのアプリのcounterをモデル内で保存して、アプリを終了して再度起動したときに、以前のカウンターが画面に出てくるようにしたいのですが、再起動時は0と表示されます。プラスボタンを押すと、以前の数字プラス１が表示されます。  
この場合何が問題か教えていただきたいです。

[code]

    import 'package:flutter/material.dart';
    import 'package:provider/provider.dart';
    import 'package:shared_preferences/shared_preferences.dart';
    
    void main() {
      runApp(
        ChangeNotifierProvider<MyHomePageModel>(
          create: (_) => MyHomePageModel(),
          child: MyApp(),
        )
      );
    }
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            primarySwatch: Colors.blue,
            visualDensity: VisualDensity.adaptivePlatformDensity,
          ),
          home: MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatelessWidget {
    
      @override
      Widget build(BuildContext context) {
        return Consumer<MyHomePageModel>(builder: (context, model, child) {
          int _counter = model.getCounter();
          return Scaffold(
              appBar: AppBar(
                title: Text('FlutteR Demo Home Page'),
              ),
              body: Center(
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    Text(
                      'You have pushed the button this many times:',
                    ),
                    Text(
                      '$_counter',
                      style: Theme.of(context).textTheme.headline4,
                    ),
                  ],
                ),
              ),
              floatingActionButton: Button());
        });
      }
    }
    
    class Button extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        final model = Provider.of<MyHomePageModel>(context, listen: false);
        return FloatingActionButton(
          onPressed: () => model.addCounter(),
          tooltip: 'Increment',
          child: Icon(Icons.add),
        );
      }
    }
    
    class MyHomePageModel extends ChangeNotifier {
      int _counter = 0;
    
      void _setPrefItems() async {
        SharedPreferences prefs = await SharedPreferences.getInstance();
        prefs.setInt('counter', _counter);
      }
    
      void _getPrefItems() async {
        SharedPreferences prefs = await SharedPreferences.getInstance();
        _counter = prefs.getInt('counter') ?? 0;
      }
    
      void addCounter() {
        _counter++;
        _setPrefItems();
        notifyListeners();
      }
    
      int getCounter() {
        _getPrefItems();
        return _counter;
      }
    }
    
[/code]


CC BY-SA 4.0
2020-09-04T05:03:25.303
70125
2020-10-12T20:37:37.930
41759
question
flutter
flutter change notifier内でのshared preferences を用いたデータの保存


なぜ質問文にあるような挙動になるかを説明します。

> 再起動時は0と表示されます。

MyHomePage の初回 build を考えます。このとき `model.getCounter();` は 0 を返します。なぜでしょうか？  
MyHomePageModel の `getCounter` 内で `_getPrefItems` が呼ばれますが、`_getPrefItems`
は非同期な関数です。`_counter = prefs.getInt('counter') ?? 0;` の前に `return _counter;`
が呼ばれます。この時点で `_counter` は初期値の 0 です。その後 MyHomePageModel の `_counter` は
`prefs.getInt('counter')` がセットされますが、 `notifyListeners` がないので MyHomePage
は再描画されません。

> プラスボタンを押すと、以前の数字プラス１が表示されます。

プラスボタンを押すと MyHomePageModel の `addCounter` が呼ばれます。このとき `_counter++` が実行され、次に
`notifyListeners` が呼ばれます。`notifyListeners` が呼ばれると、MyHomePage
は再描画され、`getCounter` は "以前の数字プラス１" を返します。

* * *

簡単な解決策としては `notifyListeners` を `_getPrefItems` に追加することが考えられます。

[code]

    void _getPrefItems() async {
      SharedPreferences prefs = await SharedPreferences.getInstance();
      _counter = prefs.getInt('counter') ?? 0;
      // 追加
      notifyListeners();
    }
    
[/code]


CC BY-SA 4.0
2020-10-12T20:37:37.930
71145
2020-10-12T20:37:37.930
32959
70125
answer