web-dev-qa-db-ja.com

Flutterでドロップダウンアイテムを選択するときのエラー

Flutterドロップダウンに問題があります。アイテムの1つを選択すると、エラーがスローされます。

別の例外がスローされました: 'package:flutter/src/material/dropdown.Dart':失敗したアサーション:481行目15: 'value == null || items.where((DropdownMenuItem item)=> item.value == 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;
}

CategoriesListのコンテンツと選択したカテゴリ(デバッガ) enter image description here

8
Alberto Méndez

私はあなたの問題を理解したと思います。これは、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をテストしますが、obj 123 ==> FeedCategory(Prueba)が見つからないため、長さ== 0です。

あなたの問題にはいくつかの解決策があります。 1つは、カテゴリやIDを比較するFeedCategoryクラスに equals operator を追加することです。

もう1つは、futurebuilderで使用されるFutureを変更する部分から分離することです。これは、futureをメンバー変数として保持する(おそらくinitStateでインスタンス化する)か、ビルダーの内部をそれに変更することで実行できます。独自のステートフルウィジェット(この場合、おそらくManageFeedSourceをStatelessWidgetにすることができます)。最後のオプションをお勧めします。

それでも問題が解決しない場合はお知らせください。それが、実際に問題が発生している理由だと確信しています。

8
rmtmckenzie

rmtmckenzie answer を完了するには、FeedCategoryオブジェクトに挿入する必要があるコードを次に示します。

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

編集:FlutterでhashCodeがどのように作成されるかを説明する link

5

エラーメッセージからは不明なドロップダウンリストに実際にはない値でドロップダウンを初期化したときに、このエラーが発生しました。

2
Austen Novis