简体   繁体   中英

Flutter Clone a List inside ChangeNotifier object

I'm using provider package as state management solution and it works pretty good.

The main object which is responsible to provide data accross the application has list variables. It is an extended ChangeNotifier object like this:

class DataSource with ChangeNotifier {...}

I have setters and getters to manage variables.

When I try to clone a list variable inside a function in DataSource class, it never actually clones the list.

void cloneList() {
  List<dynamic> list1 = [[Jack, 0], [Jane, 1]];
  List<dynamic> list2 = List.from(list1);
  list2.shuffle();
  print(list1);
  print(list2);

list1 and list2 are exactly same tables!

The interesting point about this issue is it works well when I do same operation inside my Stateless Widget!

I could find only one difference between two operations;

  1. Objet variable with ChangeNotifier
  2. Instance variables

Do you have any idea to solve this?

Note: As a bad side solution which works fine is using List.Generate function to create another list but it is difficult to manage.

Thank you very much in advance.

The problem is that List.from(...) performs a shallow copy. The content of list1 and list2 are still referencing the same objects [Jack, 0] and [Jane, 1] .

void main() {
  String jack = 'Jack';
  String jane = 'Jane';
  final listOne = [[jack, 0], [jane, 1]];
  final listTwo = List.from(listOne);
  listOne[0][0] = 'Arthur';
  listOne[0][1] = '123';
  print(listOne); // [[Arthur, 123], [Jane, 1]]
  print(listTwo); // [[Arthur, 123], [Jane, 1]]
}

One solution: Immutability

Using the Freezed package , I make my Person class immutable.

Now, I cannot change the age of a Person , instead, I have to copy that Person with the new value for age .

import 'package:freezed_annotation/freezed_annotation.dart';

part '66259238.freezed.freezed.dart';

void main() {
  Person jack = Person(name: 'Jack', age: 42);
  Person jane = Person(name: 'Jane', age: 36);
  List<Person> list1 = [jack, jane];
  List<Person> list2 = [...list1];
  // list1[0].age = 36; // COMPILATION ERROR: There isn’t a setter named 'age' in class '_$Person'.
  list1[0] = list1[0].copyWith(age: 43);
  print(list1); // [Person(name: Jack, age: 43), Person(name: Jane, age: 36)]
  print(list2); // [Person(name: Jack, age: 42), Person(name: Jane, age: 36)]
}

@freezed
abstract class Person with _$Person {
  const factory Person({String name, int age}) = _Person;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM