Добавление объекта в List Flutter

Продукт добавляется в лист, но не сохраняет продукт. При хот рестарте или переключении страниц лист становится пустой.

class ProductUi extends StatelessWidget { 
 ProductTest productTest;
  ProductUi(this.productTest);

  @override
  Widget build(BuildContext context) {
    final  productBloc = BlocProvider.of<ProductBloc>(context);
    return Scaffold(
      body: Container(
          child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(productTest.name),
            RaisedButton(
              onPressed: () {
                productBloc.add(AddToCart(productTest: productTest));
              },
              child: Text('add to cart'),
            ),
          ],
        ),
      )),
    );
  }
}

Функции

 class CartService {
     List<ProductTest> cartProduct = [];
      Future addProduct(ProductTest productTest) async {
        return cartProduct.add(productTest);      
      }
    }

блок

class ProductBloc extends Bloc<ProductEvent, ProductState> {
      CartService cartService = CartService();
      ProductBloc({@required this.cartService});
      @override
      ProductState get initialState => ProductInitial();

      @override
      Stream<ProductState> mapEventToState(ProductEvent event) async* {
        if (event is AddToCart) {
          await cartService.addProduct(event.productTest);
        }
      }
    }

Ивент

class AddToCart extends ProductEvent {
      ProductTest productTest;   
      AddToCart({this.productTest});
      @override
      List<Object> get props => [];
    }

Home screen

 class HomeScreenTest extends StatefulWidget {
      @override
      _HomeScreenTestState createState() => _HomeScreenTestState();
    }

class _HomeScreenTestState extends State<HomeScreenTest> {
  CartService cartService = CartService();

  @override
  Widget build(BuildContext context) {    
    return Scaffold(
      appBar: AppBar(
        title: Padding(
          padding: const EdgeInsets.only(top: 4),
          child: SizedBox(
            height: kToolbarHeight,
            child: Image.asset('assets/dafna_logo.png'),
          ),
        ),
        backgroundColor: Colors.blueGrey,
        elevation: 20,
      ),
      body: CategoryTest(),
    );
  }
}




  class CategoryTest extends StatefulWidget {
      @override
      _CategoryTestState createState() => _CategoryTestState();
    }

class _CategoryTestState extends State<CategoryTest> {
  CartService cartService = CartService();
  @override
  Widget build(BuildContext context) {
    BlocProvider.of<ProductBloc>(context)..add(LoadCategoriesEvent());
    return Scaffold(
      backgroundColor: Colors.blueGrey[400],
      body: SingleChildScrollView(
        child: Padding(
          padding: EdgeInsets.fromLTRB(20, 15, 20, 15),
          child: Column(
            children: <Widget>[
              Text('Категории'),
              BlocBuilder<ProductBloc, ProductState>(
                builder: (context, state) {
                  if (state is ProductLoaded) {
                    return categoryColumn(
                        state.categoriesTest, state.productTest);
                  } else {
                    return Container();
                  }
                },
              )
            ],
          ),
        ),
      ),
    );
  }

  Widget categoryColumn(
      List<CategoriesTest> categoriesTest, List<ProductTest> productTest) {
    return Column(
      children: categoriesTest.map((category) {
        return Card(
          color: Colors.blueGrey[300],
          elevation: 10.0,
          margin: EdgeInsets.fromLTRB(10, 10, 10, 10),
          child: InkWell(
            onTap: () {
              Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) => BlocProvider(
                          create: (context) =>
                              ProductBloc(cartService: cartService),
                          child: ProductList(
                            categoriesTest: category,                               
                          ))));
            },
            child: Container(
              padding: EdgeInsets.all(20),
              child: Column(
                children: <Widget>[
                  Text(
                    category.categoryname,
                  ),
                ],
              ),
            ),
          ),
        );
      }).toList(),
    );
  }


class ProductList extends StatefulWidget {
  CategoriesTest categoriesTest;
  ProductList({@required this.categoriesTest});

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

class _ProductListState extends State<ProductList> {
  CartService cartService = CartService();

  @override
  Widget build(BuildContext context) {
    BlocProvider.of<ProductBloc>(context)..add(LoadProductListEvent());
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.blueGrey,
      ),
      backgroundColor: Colors.blueGrey[100],
      body: SingleChildScrollView(
        child: Padding(
          padding: EdgeInsets.fromLTRB(20, 30, 20, 15),
          child: Column(
            children: <Widget>[
              BlocBuilder<ProductBloc, ProductState>(
                builder: (context, state) {
                  if (state is TableListLoaded) {
                    return tableListColumn(
                        state.productTest, widget.categoriesTest);
                  } else {
                    return Container();
                  }
                },
              )
            ],
          ),
        ),
      ),
    );
  }

  Widget tableListColumn(
      List<ProductTest> productTest, CategoriesTest categoriesTest) {
    return Column(
      children: productTest
          .where((product) => product.category == categoriesTest.categoryname)
          .map((product) {
        return Card(
          elevation: 10.0,

          child: InkWell(
            onTap: () {
              Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) => BlocProvider(
                          create: (context) =>
                              ProductBloc(cartService: cartService),
                          child: ProductUi(product))));
            },
            child: Container(
              padding: EdgeInsets.all(15),
              child: Column(
                children: <Widget>[
                  Image.network(product.image),
                  Text(product.name),
                ],
              ),
            ),
          ),
        );
      }).toList(),
    );
  }
}

Ответы (1 шт):

Автор решения: MiT

У вас есть класс CartService, вы создаете объект этого класса (CartService cartService = CartService();) в классе ProductUi. Данный объект существует только в данном классе. Когда данный класс уничтожается (например при хот рестарте или при переключении страницы назад) объекты в нем тоже уничтожаются.

Чтобы избежать этого, необходимо создать объект класса CartService выше по дереву виджетов и передавать его через конструктор:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final CartService cartService = CartService();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: SecondRoute(cartService),
        ),
      ),
    );
  }
}

class CartService {
  List<ProductTest> cartProduct = [];
  void addProduct(ProductTest productTest) {
    cartProduct.add(productTest);
  }
}

class ProductTest {
  final String name;
  ProductTest(this.name);
}

class SecondRoute extends StatelessWidget {
  final CartService cartService;
  SecondRoute(this.cartService);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Second Route"),
      ),
      body: Center(
        child: RaisedButton(
          onPressed: () {
            Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (context) =>
                        ProductUi(ProductTest("name"), cartService)));
          },
          child: Text("Go Next"),
        ),
      ),
    );
  }
}

class ProductUi extends StatelessWidget {
  final ProductTest productTest;
  final CartService cartService;
  ProductUi(this.productTest, this.cartService);

  @override
  Widget build(BuildContext context) {
    final productList = cartService.cartProduct;
    return Scaffold(
      body: Container(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(productTest.name),
              RaisedButton(
                onPressed: () {
                  cartService.addProduct(productTest);
                  productList.forEach((v) => print(v.name));
                  print("----");
                },
                child: Text('add to list'),
              ),
              RaisedButton(
                child: Text('go back'),
                onPressed: () {
                  Navigator.pop(context);
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Либо сделать класс CartService Singleton (предоставляет глобальную точку доступа к экземпляру класса, неубиваемый объект) и использовать его в любом месте (обращаю внимание на то что просто так создовать Singleton не стоит, так как он занимает место в памяти, и чем больше в нем объектов, тем больще места он будет занимать):

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final CartService cartService = CartService();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: SecondRoute(),
        ),
      ),
    );
  }
}

class CartService {
  static final CartService _singleton = CartService._internal();
  factory CartService() => _singleton;
  CartService._internal();

  List<ProductTest> cartProduct = [];
  void addProduct(ProductTest productTest) {
    cartProduct.add(productTest);
  }
}

class ProductTest {
  final String name;
  ProductTest(this.name);
}

class SecondRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Second Route"),
      ),
      body: Center(
        child: RaisedButton(
          onPressed: () {
            Navigator.push(
                context,
                MaterialPageRoute(
                    builder: (context) =>
                        ProductUi(ProductTest("name"))));
          },
          child: Text("Go Next"),
        ),
      ),
    );
  }
}

class ProductUi extends StatelessWidget {
  final ProductTest productTest;
  ProductUi(this.productTest);

  final CartService cartService = CartService();

  @override
  Widget build(BuildContext context) {
    final productList = cartService.cartProduct;
    return Scaffold(
      body: Container(
        child: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(productTest.name),
              RaisedButton(
                onPressed: () {
                  cartService.addProduct(productTest);
                  productList.forEach((v) => print(v.name));
                  print("----");
                },
                child: Text('add to list'),
              ),
              RaisedButton(
                child: Text('go back'),
                onPressed: () {
                  Navigator.pop(context);
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Для того чтобы сохронить данный при перезапуске приложения, необходимо ипользовать базу данных, сохронять и загружать данные с неё.

→ Ссылка