Skip to content

Null check operator used on a null value

この記事では、Flutterアプリ開発で発生する「Null check operator used on a null value」エラーについて、原因と解決方法を詳しく解説します。

問題の概要

「Null check operator used on a null value」エラーは、DartのNull Safety機能が導入されて以降、頻繁に遭遇するランタイムエラーです。このエラーは、null値を持つ可能性のある変数に対して非nullアサーション演算子(!)を使用した際に発生します。

以下のコード例のように、null許容型の変数に対して!演算子を使用すると、変数が実際にnullの場合にこのエラーが発生します:

dart
String? string; // Nullable String

void main() {
  var len = string!.length; // Runtime error: Null check operator used on a null value
}

主な解決方法

1. スタックトレースの確認

まず、エラーログを確認して、プロジェクト内のどのファイルのどの行でエラーが発生しているかを特定しましょう:

Null check operator used on a null value
#0      main (package:example/main.dart:22:16)

2. nullチェックの適切な実装

エラーが発生している場所に応じて、以下の方法で修正できます:

ローカル変数を使用したnullチェック

dart
var s = string;
if (s != null) {
  var len = s.length; // Safe 
}

null条件演算子とnull合体演算子の使用

dart
var len = string?.length ?? 0; // nullの場合はデフォルト値0を使用

特定ケース別の解決策

1. NavigatorやMediaQueryを使用している場合

非同期処理中にBuildContextにアクセスするとこのエラーが発生することがあります。mountedプロパティを確認してからアクセスしましょう:

dart
Future<void> foo() async {
  // 非同期処理
  await compute();  

  // 'context'にアクセスする前に`mounted`を確認
  if (mounted) {
    MediaQuery.of(context).size;
    Navigator.of(context).pop();  
  }
}

2. Colorのshadeを使用している場合

元の質問のコードでは、Colors.blueAccent.shade50が使用されていましたが、この色には50番目のshadeが存在しないためエラーが発生していました:

dart
// 問題のあるコード
backgroundColor: Colors.blueAccent.shade50,

// 修正後のコード
backgroundColor: Colors.blueAccent[100]!,
// または
backgroundColor: Colors.blue.shade100,

WARNING

Colorのshadeはすべての色で同じ番号が利用できるわけではありません。存在しないshadeにアクセスするとnullが返され、!演算子でエラーが発生します。

3. FutureBuilder/StreamBuilderを使用している場合

以下の2つの方法で解決できます:

型指定を行う方法

dart
FutureBuilder<List<int>>( // <-- 型 'List<int>' を指定
  future: _listOfInt(),
  builder: (_, snapshot) {
    if (snapshot.hasData) {
      List<int> myList = snapshot.data!; // <-- データの取得
    }
    return Container();
  },
)

as演算子を使用したダウンキャスト

dart
FutureBuilder(
  future: _listOfInt(),
  builder: (_, snapshot) {
    if (snapshot.hasData) {
      var myList = snapshot.data! as List<int>; // <-- 'as'を使用したキャスト
    }
    return Container();
  },
)

4. GlobalKeyを使用している場合

フォームデータを別の画面に送信するためにGlobalKeyを使用している場合:

dart
GlobalKey<FormState> _key = new GlobalKey();

var currentState = _key.currentState;
if (currentState != null) {
  currentState.validate();
  currentState.save(); // Safe
}

5. GetXを使用している場合

GetXコントローラーを適切に初期化していない場合にこのエラーが発生することがあります:

dart
late final DemoController _controller = Get.put(() => DemoController());

GetX(
  init: _controller, 
  builder: (_) => ...,
);

TIP

GetXコントローラーは以下の方法で初期化できます:

  • Get.put(YourController()) - 即時初期化
  • Get.lazyPut(() => YourController()) - 必要時に遅延初期化

6. Providerを使用している場合

Providerのアンチパターンが原因でエラーが発生することがあります:

良い例

dart
ChangeNotifierProvider(
  create: (_) => ToDoContainerModel(), // 新しいインスタンスを作成
  builder: (context, _) {
    return home;
  }
);

悪い例

dart
ChangeNotifierProvider(
  create: (_) => model, // 既存のインスタンスを再利用
  builder: (context, _) {
    return home;
  }
);

その他の一般的な解決策

1. lateキーワードの使用

null許容型(?)の代わりにlateキーワードを使用する:

dart
// 以前のコード
UserRepository? userRepository;

// 修正後のコード
late UserRepository userRepository;

2. テキスト表示時のnull処理

null値を持つ可能性のある変数をテキスト表示する場合:

dart
Text(name ?? "") // nullの場合は空文字を表示

3. Flutter環境の確認と更新

Flutterのチャンネルを安定版に切り替えて更新する:

sh
flutter channel stable
flutter upgrade
flutter pub cache repair
flutter clean

4. WidgetsFlutterBindingの初期化

get_itパッケージを使用している場合、main関数で初期化を確実に行う:

dart
Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await di.init();
  runApp(MyApp());
}

デバッグのヒント

INFO

IDEのデバッグ機能を使用すると、エラーが発生している正確な行を特定できます。ホットリロードではなく、アプリを再起動して問題が解決するか確認することも有効です。

まとめ

「Null check operator used on a null value」エラーは、DartのNull Safety機能に適切に対応していないコードで発生します。この記事で紹介した解決策を参考に、コードのnull安全性を確保しましょう。エラーが発生した場合は、スタックトレースを確認して問題の根源を特定し、適切なnullチェック方法を適用することが重要です。

Null Safetyはコードの品質と安全性を高める強力な機能です。正しく活用することで、ランタイムエラーを減らし、より堅牢なアプリケーションを開発できます。