Flutter 颤振:Image.memory()以字节失败!=空';:不正确——当有数据时
我试图根据来自后端的(base64)数据显示一个图像,但我一直收到错误Flutter 颤振:Image.memory()以字节失败!=空';:不正确——当有数据时,flutter,dart,Flutter,Dart,我试图根据来自后端的(base64)数据显示一个图像,但我一直收到错误bytes!=null”:不正确。 这是我的密码: class _FuncState extends State<Func> { Uint8List userIconData; void initState() { super.initState(); updateUI(); } void updateUI() async { await getUserIconDat
bytes!=null”:不正确。
这是我的密码:
class _FuncState extends State<Func> {
Uint8List userIconData;
void initState() {
super.initState();
updateUI();
}
void updateUI() async {
await getUserIconData(1, 2, 3).then((value) => userIconData = value);
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
Container(
child: CircleAvatar(
backgroundImage: Image.memory(userIconData).image, // <--- problem here
maxRadius: 20,
),
),
),
);
}
}
class\u FuncState扩展了状态{
UINT8列出用户数据;
void initState(){
super.initState();
updateUI();
}
void updateUI()异步{
等待getUserIconda(1,2,3),然后((value)=>UserIconda=value);
}
@凌驾
小部件构建(构建上下文){
返回安全区(
孩子:脚手架(
容器(
孩子:圆环星(
backgroundImage:Image.memory(usericonda.Image,//错误消息对我来说非常清楚。usericonda
在传递给Image.memory
构造函数时为null
在渲染图像之前,可以使用或使用一个条件来检查usericonda
是否为空,如果为空,则手动显示加载指示器,或者沿着这些线显示。此外,您还需要实际设置触发重新渲染的状态。不过,我会使用前者。这非常简单;如果您查看代码,您应该能够完成这一系列操作
小部件已创建。无操作。此时usericonda为空
initState
被调用。异步http调用被启动。usericonda==null
调用build
。生成发生,抛出错误。usericonda==null
http调用返回。usericonda已设置。usericonda==您的图像
由于未调用setState
,生成函数将不会再次运行。如果您这样做,则会发生这种情况(但您之前仍然存在异常)
调用build
。usericonda已设置。usericonda==您的图像
这里的关键是理解异步调用(任何返回未来并可选地使用async
和await
的调用)不要立即返回,而是在稍后的某个时间返回,您不能指望他们同时设置了您需要的内容。如果您以前尝试过使用从磁盘加载的图像执行此操作,并且成功了,那只是因为Flatter执行了一些仅在从磁盘加载是同步的情况下才可能执行的技巧
这里有两个选项可以帮助您编写代码
class\u FuncState扩展了状态{
UINT8列表?用户图标数据;
//如果您正在使用“func”小部件中的任何数据,请改用此小部件
//在小部件发生更改的情况下初始化状态。
//您还可以检查旧的与新的,如果没有变化
//这需要重新加载,而不是重新加载。
@凌驾
void didUpdateWidget(Func oldWidget){
super.didUpdateWidget(oldWidget);
updateUI();
}
void updateUI()异步{
等待getUserIconData(widget.role、widget.id、widget.session)。然后((值){
//这确保了重建的发生
设置状态(()=>usericonda=value);
});
}
@凌驾
小部件构建(构建上下文){
返回安全区(
孩子:脚手架(
主体:容器(
//如果图像已加载,则仅使用圆形化身,否则
//显示加载指示器。
子项:usericonda!=null?CircleAvatar(
背景图片:Image.memory(usericonda!).Image,
最大半径:20,
):CircularProgressIndicator(),
),
),
);
}
}
做同样事情的另一种方法是使用FutureBuilder
class\u FuncState扩展了状态{
//晚用并不完全安全,但我们可以相信
//以前总是叫didUpdateWidget
//建立这样的工作。
未来用户数和未来数;
@凌驾
void didUpdateWidget(Func oldWidget){
super.didUpdateWidget(oldWidget);
用户图标未来=
getUserIconda(widget.role、widget.id、widget.session);
}
@凌驾
小部件构建(构建上下文){
返回安全区(
孩子:脚手架(
主体:容器(
孩子:未来建设者(
未来:UserICondaFuture,
生成器:(BuildContext上下文,异步快照){
if(snapshot.hasData){
返回圆(
背景图片:图片。内存(快照。数据!)。图片,
最大半径:20);
}否则{
返回循环ProgressIndicator();
}
},
),
),
),
);
}
}
请注意,加载指示器只是一个选项;实际上,我建议为您的化身(即灰色“用户”图像)设置一个硬编码的默认值,在加载图像时将其关闭
请注意,我在这里使用了空安全代码,因为这将使此答案具有更好的使用寿命,但要切换回非空安全代码,您只需删除代码中多余的?
、!
和后期的。非常清楚的解释,谢谢。我会尝试一下。这非常有效-我非常接近。谢谢您轻推。
Future<Uint8List> getUserIconData(
role,
id,
session,
) async {
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);
return base64Decode(data['img']);
}
return null;
}