You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter问题:存在图片数据时Image.memory()仍报‘bytes != null’: is not true错误

解决Flutter中Image.memory抛出‘bytes != null’断言错误的方案

我一眼就看出问题出在哪了——你忽略了Flutter中异步操作的执行顺序,还有状态更新的核心逻辑!

问题根源

你的userIconData一开始是未初始化的null,initState里调用的updateUI是异步方法,它不会阻塞build方法的执行。所以第一次渲染UI的时候,userIconData还没拿到后端返回的字节数据,这时候把null传给Image.memory(),自然触发了bytes != null的断言错误。哪怕后续异步请求成功拿到了数据,你也没调用setState通知框架重新构建UI,数据更新了UI也不会跟着刷新。

另外,你的getUserIconData函数在请求失败时会直接返回null,这也埋下了后续报错的隐患。

具体修复方案

我给你调整了代码,一次性解决这几个问题:

  1. 明确变量可空性:避免首次build时传入null
  2. 异步获取数据后调用setState:让框架感知数据变化,触发UI重建
  3. 处理请求异常与无效数据:避免空值流入UI层

修改后的状态类代码

class _FuncState extends State<Func> {
  Uint8List? userIconData; // 标记为可空类型,明确表示初始状态为null

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

  void updateUI() async {
    // 用try-catch捕获请求异常
    try {
      final iconData = await getUserIconData(1, 2, 3);
      // 拿到数据后调用setState更新状态,触发UI重建
      setState(() {
        userIconData = iconData;
      });
    } catch (e) {
      print('获取头像失败: $e');
      // 异常时可以设置默认头像,或保持null显示占位
      setState(() {
        userIconData = null;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        body: Container(
          child: CircleAvatar(
            // 判断数据是否存在,不为null才显示网络头像,否则用本地默认图
            backgroundImage: userIconData != null 
                ? Image.memory(userIconData!).image 
                : AssetImage('assets/default_avatar.png'), // 替换成你的默认头像路径
            maxRadius: 20,
          ),
        ),
      ),
    );
  }
}

优化后的辅助函数

Future<Uint8List?> getUserIconData(
  role, id, session,
) async {
  try {
    var url = Uri.https(kMobileAppAPIURL, kMobileAppAPIFolder);
    var response = await http.post(url, body: {
      'method': 'getUserProfilePic',
      'a': id.toString(),
      'b': role.toString(),
      'c': session.toString(),
    });
    if (response.statusCode == 200) {
      Map data = jsonDecode(response.body);
      // 额外校验img字段的有效性,避免解码空字符串报错
      if (data.containsKey('img') && data['img'] != null && data['img'].isNotEmpty) {
        return base64Decode(data['img']);
      }
    }
  } catch (e) {
    print('请求头像接口异常: $e');
  }
  // 请求失败或数据无效时返回null,也可以返回默认头像的base64解码字节
  return null;
}

额外简化方案:用FutureBuilder替代手动状态管理

如果你觉得手动管理setState太繁琐,可以用FutureBuilder简化异步数据的UI渲染,代码会更简洁:

@override
Widget build(BuildContext context) {
  return SafeArea(
    child: Scaffold(
      body: Container(
        child: FutureBuilder<Uint8List?>(
          future: getUserIconData(1, 2, 3),
          builder: (context, snapshot) {
            if (snapshot.hasData && snapshot.data != null) {
              return CircleAvatar(
                backgroundImage: Image.memory(snapshot.data!).image,
                maxRadius: 20,
              );
            } else if (snapshot.hasError) {
              // 错误状态显示默认头像
              return CircleAvatar(
                backgroundImage: AssetImage('assets/default_avatar.png'),
                maxRadius: 20,
              );
            }
            // 加载中显示进度条
            return CircularProgressIndicator();
          },
        ),
      ),
    ),
  );
}

这样修改后,不仅解决了当前的断言错误,还让代码的健壮性提升了不少,能处理接口请求失败、数据为空等各种异常情况。

内容的提问来源于stack exchange,提问作者Henry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 11:57:33