Abhinav Kumar deb
Abhinav Kumar deb

Reputation: 11

How to do state restoration in flutter?

I made an Expense Tracker app which has a List named '_registeredExpenses'. This list stores all the expenses to be displayed when the app is opened . Now my problem is that when i kill the app , it doesnot store the added values or the deleted values . It just reverts back to its original state (original state has two hardcoded rows i.e handwash and cinema).

i tried to implement state restoration by extending the class RestorationMixin and then following the approach given in this video :https://youtu.be/5-u5VjPJsNI

Now my problem is that i wanted to convert the List named '_registeredExpenses' to a type of Restorable property so that it could be recieved as property argument by the registerForRestoration method (as is the approach given in the youtube video) , But so far all i get is error.enter image description here

it is saying this :

The argument type 'List<Expense>' can't be assigned to the parameter type 'RestorableProperty<Object?>'.dart argument_type_not_assignable

below are two images from my app: First pic shows the state after adding an expense titled 'Milk' and before kiling the app.

Second pic shows the state after kiling the app and restarting it.

enter image description here enter image description here

I got the app to run by commenting out the error area( So that i could show what i am talking about ).

below is my code snippet where I implemented the RestorationMixin :

import 'package:expense_tracker/main.dart';
import 'package:expense_tracker/widgets/chart/chart.dart';
import 'package:expense_tracker/widgets/new_expense.dart';
import 'package:flutter/material.dart';
import 'package:expense_tracker/models/expense.dart';
import 'package:expense_tracker/widgets/expenses_list/expenses_list.dart';


class Expenses extends StatefulWidget {
  const Expenses({super.key});
  @override
  State<Expenses> createState() {
    return _ExpensesState();
  }
}

class _ExpensesState extends State<Expenses> with RestorationMixin {
  final List<Expense> _registeredExpenses = [
    Expense(
      title: 'Handwash',
      amount: 19.99,
      date: DateTime.now(),
      category: Category.hygiene,
    ),
    Expense(
      title: 'Cinema',
      amount: 150.69,
      date: DateTime.now(),
      category: Category.leisure,
    ),
  ];

  void _openAddExpenseOverlay() {
    showModalBottomSheet(
        isScrollControlled:
            true, //this ensures that the overlay takes full space available
        context: context,
        builder: (ctx) {
          return NewExpense(onAddExpense: _addExpense);
        });
  }

  void _addExpense(Expense expense) {
    setState(() {
      _registeredExpenses.add(expense);
    });
  }

  void _removeExpense(Expense expense) {
    final expenseIndex = _registeredExpenses.indexOf(expense);
    setState(() {
      _registeredExpenses.remove(expense);
    });
    ScaffoldMessenger.of(context)
        .clearSnackBars(); //clears any info message of prior deletions
    ScaffoldMessenger.of(context).showSnackBar(SnackBar(
      duration: const Duration(seconds: 4),
      content: const Text("Expense deleted"),
      action: SnackBarAction(
        textColor: Colors.lightBlue,
        label: "Undo",
        onPressed: () {
          setState(() {
            // if undo pressed , insert the expense back
            _registeredExpenses.insert(expenseIndex, expense);
          });
        },
      ),
    ));
  }

  @override
  Widget build(BuildContext context) {
    Widget mainContent = const Center(
      child: Text("No expenses found. Kindly start adding. "),
    );

    if (_registeredExpenses.isNotEmpty) {
      mainContent = ExpensesList(
        expenses: _registeredExpenses,
        onRemoveExpense: _removeExpense,
      );
    }
    return Scaffold(
      appBar: AppBar(
        //backgroundColor: Colors.blueGrey,
        title: const Text("e-KHATA"),
        actions: [
          IconButton(
              onPressed: _openAddExpenseOverlay,
              icon: const Icon(
                Icons.add_rounded,
                //color: Colors.deepOrange,
              ))
        ],
      ),
      body: Column(
        children: [
          Chart(expenses: _registeredExpenses),
          Expanded(child: mainContent)
        ],
      ),
    );
  }

  @override
  String? get restorationId => "RegdExpensesList";

  @override
  void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
    registerForRestoration(_registeredExpenses, "RegD_Expenses");
  }
}

The error is Coming in the registerForRestoration method inside the restoreState method .

Please guide me . I am new to flutter . I have tried a lot but i don't know what to do.

Upvotes: 1

Views: 911

Answers (1)

SempaiLeo
SempaiLeo

Reputation: 344

You need to make a custom restorable for your data type: Checkout this code example https://api.flutter.dev/flutter/widgets/RestorableValue-class.html

Although I would reccomend keeping the state persisted somewhere else. Checkout Riverpod and it's StateProvider for an extremely easy solution.

Upvotes: 0

Related Questions