Ошибка при выборе выпадающего элемента в Flutter - PullRequest
0 голосов
/ 28 августа 2018

У меня проблема с выпадающим списком Flutter. Когда я выбираю один из пунктов, он выдает ошибку:

Было сгенерировано еще одно исключение: 'package: flutter / src / material / dropdown.dart': Неудачное утверждение: строка 481, позиция 15: 'value == null || items.where ((DropdownMenuItem item) => item.value == значение) .length == 1 ': не соответствует действительности.

Я искал, и люди говорят, что эта ошибка вызвана тем, что выбранный элемент не принадлежит исходному списку, но после некоторой отладки я вижу, что это так. Я не могу найти источник этой ошибки, поэтому буду признателен за любую помощь.

Вот мой код

Модель FeedCategory

import 'package:meta/meta.dart';

class FeedCategory {
  static final dbId = "id";
  static final dbName = "name";

  int id;
  String name;

  FeedCategory({this.id, @required this.name});

  FeedCategory.fromMap(Map<String, dynamic> map)
      : this(
    id: map[dbId],
    name: map[dbName],
  );

  Map<String, dynamic> toMap() {
    return {
      dbId: id,
      dbName: name,
    };
  }

  @override
  String toString() {
    return 'FeedCategory{id: $id, name: $name}';
  }
}

Виджет

import 'package:app2date/repository/repository.dart';
import 'package:app2date/model/FeedSource.dart';
import 'package:app2date/model/FeedCategory.dart';
import 'package:app2date/util/ui.dart';
import 'package:flutter/material.dart';

class ManageFeedSource extends StatefulWidget {
  ManageFeedSource({Key key, this.feedSource}) : super(key: key);

  final FeedSource feedSource;

  @override
  _ManageFeedSource createState() => new _ManageFeedSource();
}

class _ManageFeedSource extends State<ManageFeedSource> {
  FeedCategory _feedCategory;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('New Feed'),
      ),
      body: new FutureBuilder(
        future: Repository.get().getFeedCategories(),
        builder: (BuildContext context, AsyncSnapshot snapshot) {
          List<FeedCategory> categoriesList = snapshot.data;
          if (categoriesList != null) {
            return new DropdownButton<FeedCategory>(
              hint: Text('Choose category...'),
              value: _feedCategory,
              items: categoriesList.map((FeedCategory category) {
                return DropdownMenuItem<FeedCategory>(
                  value: category,
                  child: Text(category.name),
                );
              }).toList(),
              onChanged: (FeedCategory category) {
                print('Selected: $category');
                setState(() {
                  _feedCategory = category;
                });
              },
            );
          } else {
            return Container(
              decoration: new BoxDecoration(color: Colors.white),
            );
          }
        },
      ),
    );
  }

  @override
  void initState() {
    super.initState();
  }
}

Репозиторий, метод getFeedCategories

Future<List<FeedCategory>> getFeedCategories() async {
  return await database.getFeedCategories();
}

Метод базы данных getFeedCategories

Future<List<FeedCategory>> getFeedCategories() async {
  var dbClient = await db;
  var query = "SELECT * FROM $feedCategoryTableName;";
  var result = await dbClient.rawQuery(query);
  List<FeedCategory> feedCategories = [];
  for (Map<String, dynamic> item in result) {
    feedCategories.add(new FeedCategory.fromMap(item));
  }
  return feedCategories;
}

Содержимое категорийList и выбранная категория (отладчик) enter image description here

Ответы [ 3 ]

0 голосов
/ 04 апреля 2019

Чтобы завершить ответ rmtmckenzie , вот код, который вы должны вставить в свой объект FeedCategory:

bool operator ==(o) => o is FeedCategory && o.name == name;
int get hashCode => name.hashCode;

Редактировать: A ссылка , объясняющая, для чего сделан хэш-код в Flutter

0 голосов
/ 08 июня 2019

Я получил эту ошибку, когда инициализировал раскрывающийся список значением, которого на самом деле не было в раскрывающемся списке, что было неясно из сообщения об ошибке.

0 голосов
/ 28 августа 2018

Думаю, я понял вашу проблему. Это связано с тем, как вы используете FutureBuilder.

Вот что я думаю:

  1. Ваше приложение работает. Это делает вызов getFeedCategories ()
  2. Будущее завершается, составляется список и т. Д. Со следующими элементами:

    obj 123 ==> FeedCategory(Prueba), obj 345 ==> FeedCategory(Categories 2)

  3. Вы выбираете элемент из выпадающего списка, setState () называется

    Ваша _feedCategory теперь равна obj 123 ==> FeedCategory(Prueba)

  4. Виджет перестроен. Это делает еще один вызов getFeedCategories ()

  5. Будущее завершено, список построен и т. Д. Со следующими элементами

    obj 567 ==> FeedCategory(Prueba), obj 789 ==> FeedCategory(Categories 2)

  6. Тест выпадающего списка items.where((DropdownMenuItem item) => item.value == value).length == 1, но длина == 0, потому что obj 123 ==> FeedCategory(Prueba) не найден.

Есть несколько решений вашей проблемы. Можно было бы добавить оператор равно к вашему классу FeedCategory, который сравнивает категорию и / или идентификатор.

Другим вариантом было бы отделить Future, используемое в futurebuilder, от изменяемой части - вы можете сделать это, сохранив будущее как переменную-член (возможно, создайте его экземпляр в initState?), Или сделав внутреннюю часть встроенный в собственный виджет Stateful (в этом случае вы, вероятно, можете сделать ManageFeedSource StatelessWidget). Я бы порекомендовал последний вариант.

Дайте мне знать, если это не решит вашу проблему, но я уверен, что именно поэтому он делает то, что делает.

...