Flutter アプリ

【Flutter】sqfliteのデータ取得が失敗した時の対処方法(Null check operator used on a null value)

sqfliteに格納しているデータを参照するときに、★行目で以下のエラーメッセージが表示され、アプリが起動しませんでした。

Exception has occurred.
_CastError (Null check operator used on a null value)

該当のファイルは以下の通りです。

      body:Center(
        child: FutureBuilder<List<Map<String, dynamic>>>(
          future: dbProvider.getCountCategory("肩"),
          builder: (BuildContext context, AsyncSnapshot<List<Map<String, dynamic>>> snapshot) {
              var data = snapshot.data;
              var datalength = data!.length; ★
              return Text(datalength.toString());
            }

本記事では、 そのエラーの原因と対処方法を紹介します。

本記事の想定読者

  • Flutterでアプリを開発している人

開発環境

$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 3.0.5, on Microsoft Windows [Version 10.0.19045.3208], locale ja-JP)
[√] Android toolchain - develop for Android devices (Android SDK version 32.0.0)
[√] Chrome - develop for the web
[√] Visual Studio - develop for Windows (Visual Studio Community 2022 17.1.4)
[√] Android Studio (version 2021.1)
[!] Android Studio (version 4.1)
    X Unable to determine bundled Java version.
[!] Android Studio (version 4.2)
    X Unable to determine bundled Java version.
[√] VS Code (version 1.81.0)
[√] Connected device (4 available)
[√] HTTP Host Availability

! Doctor found issues in 2 categories.

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter


  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.2
  sticky_grouped_list: ^3.1.0
  intl: ^0.18.1
  google_fonts: ^4.0.4
  sqflite: ^2.0.3+1
  numberpicker: ^2.1.2

原因

このエラーは、Null check operator (null安全演算子) ! がNullの値に対して使用された場合に発生します。このエラーは、snapshot.dataがNullである場合にdatalengthnullが代入されるためです。

FutureBuilderのfutureが完了する前にWidgetが描画される可能性があるため、snapshot.dataがまだ利用できない状態でsnapshot.data.lengthを参照しているのでエラーが発生しています。

対処方法

この問題を解決するために、FutureBuilderウィジェットがデータを取得する前にローディング状態を表示したり、データの取得に失敗した場合にエラーをハンドリングしたりすることが重要です。

      body:Center(
        child: FutureBuilder<List<Map<String, dynamic>>>(
          future: dbProvider.getCountCategory("肩"),
          builder: (BuildContext context, AsyncSnapshot<List<Map<String, dynamic>>> snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
              return CircularProgressIndicator(); // データ取得中はローディング表示
            } else if (snapshot.hasError) {
              return Text("データの取得に失敗しました"); // エラーハンドリング
            } else {
              var data = snapshot.data;
              var datalength = data!.length;
              return Text(datalength.toString());
            }
          },
        ),

上記の修正により、FutureBuilderウィジェットがデータを取得中の場合にはローディングインジケーターが表示され、データの取得に失敗した場合にはエラーメッセージが表示されるようになります。データが取得できた場合には正常に表示されます。

-Flutter, アプリ