Null Safety Error: 在Flutter Riverpod中无条件访问 ‘state’ 属性

huangapple go评论67阅读模式
英文:

Null Safety Error: Unconditionally accessing 'state' property in Flutter Riverpod

问题

我在尝试访问'state'属性时,在我的Flutter Riverpod代码中遇到了一个空安全错误。错误消息如下:

"The property 'state' can't be unconditionally accessed because the receiver can be 'null'. Try making the access conditional (using '?') or adding a null check to the target ('!')."

主要目标是使用Riverpod作为状态管理解决方案来更新图像,以确保在Web浏览器和移动设备上都能无缝运行。

我有以下代码片段演示了这个问题:

import 'dart:io';
import 'dart:typed_data';
import 'package:provider/provider.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

final pickedImageProvider = StateProvider<File?>((ref) => null);
final webImageProvider = StateProvider<Uint8List>((ref) => Uint8List(8));
final tapOffsetProvider = StateProvider<Offset?>((ref) => null);

class ProfileAppBar extends ConsumerWidget {
  const ProfileAppBar({Key? key}) : super(key: key);

  Future<void> _pickImage(BuildContext context) async {
    if (!kIsWeb) {
      final ImagePicker picker = ImagePicker();
      XFile? image = await picker.pickImage(source: ImageSource.gallery);
      if (image != null) {
        var selected = File(image.path);
        context.read(pickedImageProvider).state = selected;
      } else {
        print('No image has been picked');
      }
    } else if (kIsWeb) {
      final ImagePicker picker = ImagePicker();
      XFile? image = await picker.pickImage(source: ImageSource.gallery);
      if (image != null) {
        var f = await image.readAsBytes();
        context.read(webImageProvider).state = f;
        context.read(pickedImageProvider).state = File('a');
      } else {
        print('No image has been picked');
      }
    } else {
      print('Something went wrong');
    }
  }

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return SafeArea(
      child: Scaffold(
        appBar: AppBar(
          // 这里是AppBar的设置
        ),
        // 其他部分的设置
      ),
    );
  }
}

错误具体发生在_pickImage方法中,当我尝试设置context.read().state的状态时。我应该如何调整我的代码以使对'state'属性的访问是有条件的,或者应该如何适当地添加一个空检查以避免此错误?

英文:

I'm encountering a null safety error in my Flutter Riverpod code when trying to access the 'state' property. The error message says:

"The property 'state' can't be unconditionally accessed because the receiver can be 'null'.
Try making the access conditional (using '?.') or adding a null check to the target ('!')."

The main goal is to update the image using Riverpod as the state management solution, ensuring it works seamlessly on both web browsers and mobile devices.

I have the following code snippet that demonstrates the issue:

import &#39;dart:io&#39;;
import &#39;dart:typed_data&#39;;
import &#39;package:provider/provider.dart&#39;;
import &#39;package:flutter/foundation.dart&#39;;
import &#39;package:flutter/material.dart&#39;;


final pickedImageProvider = StateProvider&lt;File?&gt;((ref) =&gt; null);
final webImageProvider = StateProvider&lt;Uint8List&gt;((ref) =&gt; Uint8List(8));
final tapOffsetProvider = StateProvider&lt;Offset?&gt;((ref) =&gt; null);

class ProfileAppBar extends ConsumerWidget {
  const ProfileAppBar({Key? key}) : super(key: key);

  Future&lt;void&gt; _pickImage(BuildContext context) async {
    if (!kIsWeb) {
      final ImagePicker picker = ImagePicker();
      XFile? image = await picker.pickImage(source: ImageSource.gallery);
      if (image != null) {
        var selected = File(image.path);
        context.read(pickedImageProvider).state = selected;
      } else {
        print(&#39;No image has been picked &#39;);
      }
    } else if (kIsWeb) {
      final ImagePicker picker = ImagePicker();
      XFile? image = await picker.pickImage(source: ImageSource.gallery);
      if (image != null) {
        var f = await image.readAsBytes();
        context.read(webImageProvider).state = f;
        context.read(pickedImageProvider).state = File(&#39;a&#39;);
      } else {
        print(&#39;No image has been picked &#39;);
      }
    } else {
      print(&#39;Something went wrong&#39;);
    }
  }

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return SafeArea(
      child: Scaffold(
        appBar: AppBar(
          ...   Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: [
                  Tooltip(
                    message: &#39;Settings&#39;,
                    child: Semantics(
                      label: &#39;Pomodoro timer settings&#39;,
                      enabled: true,
                      readOnly: true,
                      child: IconButton(
                        icon: const Icon(
                          Icons.settings_outlined,
                          color: Color(0xff3B3B3B),
                          size: 24,
                          semanticLabel: &#39;Pomodoro timer Settings&#39;,
                        ),
                        onPressed: () {
                          Navigator.push(
                            context,
                            MaterialPageRoute(
                              builder: (context) =&gt; const Scaffold(),
                            ),
                          );
                        },
                      ),
                    ),
                  ),
                  GestureDetector(
                    behavior: HitTestBehavior.translucent,
                    onTapDown: (details) {
                      ref.read(tapOffsetProvider).state =
                          details.globalPosition;
                    },
                    child: IconButton(
                      onPressed: () {
                        final tapOffset = ref.watch(tapOffsetProvider).state;
                        if (tapOffset != null) {
                          showMenu(
                            position: RelativeRect.fromLTRB(
                              tapOffset!.dx - 150,
                              64,
                              tapOffset.dx ?? 0,
                              0,
                            ),
                            constraints: const BoxConstraints(
                              maxWidth: 600,
                            ),...
        ),
      ),
    );
  }
}

The error occurs specifically in the _pickImage method when I try to set the state of context.read().state. How should I adjust my code to make the access to the 'state' property conditional or how should I properly add a null check to avoid this error?

答案1

得分: 1

你的代码应该工作正常!我只看到一个按钮的问题:

IconButton(
onPressed: () {
  final tapOffset = ref.read(tapOffsetProvider); // 在回调中必须使用 `ref.read`
  if (tapOffset != null) {...}

要使用你的提供程序,只需在值确保不为 null 时添加 !,或者使用 ?

final pickedImageProvider = StateProvider<File?>((ref) => null);

{
  File? pickedImage = ref.read(pickedImageProvider);
  File pickedImageNotNull = ref.read(pickedImageProvider)!;

  String? pickedImagePath = ref.read(pickedImageProvider)?.path;
  String pickedImagePathNotNull = ref.read(pickedImageProvider)!.path;
}

但是,你真正的问题是忘记使用 .notifier 并且没有正确地尝试访问状态:

context.read(pickedImageProvider.notifier).state = selected;
context.read(webImageProvider.notifier).state = f;
context.read(pickedImageProvider.notifier).state = File('a');

// 或者这样做:
context.read(pickedImageProvider.notifier).update((_) => selected);
context.read(webImageProvider.notifier).update((_) => f);
context.read(pickedImageProvider.notifier).update((_) => File('a'));

这些是你提供的代码片段的翻译。

英文:

Your code should work fine! I see only one problem with the button:

IconButton(
onPressed: () {
final tapOffset = ref.read(tapOffsetProvider); // `state` don&#39;t required
if (tapOffset != null) {...}

In callbacks it is necessary to use ref.read.


To use your providers, just add ! if you are sure the value is not null or use ?.

final pickedImageProvider = StateProvider&lt;File?&gt;((ref) =&gt; null);
{
File? pickedImage = ref.read(pickedImageProvider);
File pickedImageNotNull = ref.read(pickedImageProvider)!;
String? pickedImagePath = ref.read(pickedImageProvider)?.path;
String pickedImagePathNotNull = ref.read(pickedImageProvider)!.path;
}

But really your problem is that you forgot to use the .notifier and are not correctly trying to access the state:

context.read(pickedImageProvider.notifier).state = selected;
context.read(webImageProvider.notifier).state = f;
context.read(pickedImageProvider.notifier).state = File(&#39;a&#39;);
// Or do it this way:
context.read(pickedImageProvider.notifier).update((_) =&gt; selected);
context.read(webImageProvider.notifier).update((_) =&gt; f);
context.read(pickedImageProvider.notifier).update((_) =&gt; File(&#39;a&#39;));

huangapple
  • 本文由 发表于 2023年6月16日 09:12:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/76486391.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定