【问题标题】:Flutter App with provider and persistent storageFlutter App with provider and persistent storage
【发布时间】:2022-12-19 05:43:37
【问题描述】:

I have been trying to figure out how to build an app in flutter with persistant state manager. I can't seem to get it to work. This is my app with a state manager.

I want to store actual classes, and not just an integer, which makes this a bit tricker, but hey, that's my goal.

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

void main() {
  runApp(
    /// Use a provider. Multiprovider works just fine
    MultiProvider(
      providers: [
        ChangeNotifierProvider(create: (_) => State()),
      ],
      child: const MyApp(),
    ),
  );
}

// Define the data type we want to use
// We will use time and value to track data over time
class MyData {
  final DateTime time;
  final int value;
  MyData(this.time, this.value);
}

// Use a state with a change notifier (provider stuff)
class State with ChangeNotifier {
  late List<MyData> _dataset = [];
  List<MyData> get dataset => _dataset;

  State() {
    // The dataset is a list of objects
    _dataset = [];
  }

  void addData(time, value) {
    // Add data to the dataset
    MyData datapoint = MyData(time, value);
    _dataset.add(datapoint);
  }

  void clearData() {
    // Clear the dataset
    _dataset = [];
  }
}

// The actual widget
class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Example'),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text('You have added this many datapoints'),
            const Count(),
            IconButton(
                onPressed: () =>
                    context.read<State>().addData(DateTime.now(), 100),
                icon: const Icon(Icons.add)),
            IconButton(
                onPressed: () => context.read<State>().clearData(),
                icon: const Icon(Icons.remove))
          ],
        ),
      ),
    );
  }
}

// And the parsing of the data to a widget
class Count extends StatelessWidget {
  const Count({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Text(
      /// Calls `context.watch` to make [Count] rebuild when [Counter] changes.
      '${context.watch<State>().dataset.length}',
      key: const Key('counterState'),
      style: Theme.of(context).textTheme.headlineMedium,
    );
  }
}

The question is. How can I add a persistent logic to this?

【问题讨论】:

    标签: flutter dart state persistence


    【解决方案1】:

    The persistent data can be added in the initialization of the state. In order to save the data in a Key-value storage, each object needs to be stringified using something like json.encode and json.decode.

    Here's an updated code sn-p that will work.

    I removed your comment, and added cmets wherever I added code that will add the persistence logic.

    import 'package:flutter/material.dart';
    import 'package:provider/provider.dart';
    // Add shared_preferences and convert
    import 'package:shared_preferences/shared_preferences.dart';
    import 'dart:convert';
    
    void main() {
      runApp(
        MultiProvider(
          providers: [
            ChangeNotifierProvider(create: (_) => State()),
          ],
          child: const MyApp(),
        ),
      );
    }
    
    class MyData {
      final DateTime time;
      final int value;
      MyData(this.time, this.value);
    
      // Add a converter to from JSON
      static MyData fromJSON(Map<String, dynamic> jsonData) {
        return MyData(DateTime.fromMillisecondsSinceEpoch(jsonData["time"]),
            jsonData["value"]);
      }
    
      // Add a converter to from an encoded JSON string
      static MyData fromJSONString(String jsonDataString) {
        Map<String, dynamic> jsonData = json.decode(jsonDataString);
        return MyData.fromJSON(jsonData);
      }
    
      // Add a converter to JSON
      dynamic toJSON() {
        return {"time": time.millisecondsSinceEpoch, "value": value};
      }
    
      // Add a converter to JSON string
      String toJSONString() {
        return json.encode(toJSON());
      }
    }
    
    class State with ChangeNotifier {
      late List<MyData> _dataset = [];
      List<MyData> get dataset => _dataset;
    
      State() {
        _dataset = [];
        // Read the data on the creation of a state
        readData();
      }
    
      void readData() async {
        // Load the data from the shared preferences
        final prefs = await SharedPreferences.getInstance();
        List<String>? datasetStrings = prefs.getStringList("dataset");
        datasetStrings ??= [];
    
        // Load the data into the state
        _dataset = datasetStrings
            .map((jsonData) => MyData.fromJSONString(jsonData))
            .toList();
    
        // Notify the listeners
        notifyListeners();
      }
    
      void setData() async {
        // Load the shared preferences
        final prefs = await SharedPreferences.getInstance();
    
        // Load the data into the shared preferences
        List<String> datasetStrings =
            _dataset.map((dataPoint) => dataPoint.toJSONString()).toList();
        await prefs.setStringList("dataset", datasetStrings);
      }
    
      void addData(time, value) {
        MyData dataPoint = MyData(time, value);
        _dataset.add(dataPoint);
        // Save the data and notify listeners
        setData();
        notifyListeners();
      }
    
      void clearData() {
        _dataset = [];
        setData();
        notifyListeners();
      }
    }
    
    class MyApp extends StatelessWidget {
      const MyApp({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return const MaterialApp(
          home: MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatelessWidget {
      const MyHomePage({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('Example'),
          ),
          body: Center(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                const Text('You have pushed the button this many times:'),
                const Count(),
                IconButton(
                    onPressed: () =>
                        context.read<State>().addData(DateTime.now(), 100),
                    icon: const Icon(Icons.add)),
                IconButton(
                    onPressed: () => context.read<State>().clearData(),
                    icon: const Icon(Icons.remove)),
                // Also add a refresh button to test
                // loading of data without losing debugging connection
                IconButton(
                    onPressed: () => context.read<State>().readData(),
                    icon: const Icon(Icons.refresh))
              ],
            ),
          ),
        );
      }
    }
    
    class Count extends StatelessWidget {
      const Count({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Text(
          /// Calls `context.watch` to make [Count] rebuild when [Counter] changes.
          '${context.watch<State>().dataset.length}',
          key: const Key('counterState'),
          style: Theme.of(context).textTheme.headlineMedium,
        );
      }
    }
    
    
    

    【讨论】:

      猜你喜欢
      • 2021-05-17
      • 2020-10-29
      • 2022-12-26
      • 2020-10-12
      • 2022-10-07
      • 2021-05-14
      • 1970-01-01
      • 1970-01-01
      • 2023-01-31
      相关资源
      最近更新 更多