如何解决如何在 Flutter 中使用 FutureBuilder 动态构建富文本
我试图在一段文本中查找“@”,然后异步收集该标签的 displayName。我遇到的问题是我的 FutureBuilder 不断返回 null。
我得到的错误是这样的。
======== 小部件库捕获的异常========
在构建 FutureBuilder(dirty,state: _FutureBuilderState#151f7) 时抛出了以下断言: 构建函数返回 null。
有问题的小部件是:FutureBuilder 构建函数绝不能返回 null。
我的代码是这样的:
Container(
width: double.infinity,child: FutureBuilder(
initialData: SelectableText(''),future: buildSelectableText(context),builder: (BuildContext context,AsyncSnapshot<SelectableText> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return Center(child: CircularProgressIndicator());
return snapshot.data;
}
),),Future<SelectableText> buildSelectableText(BuildContext context) async {
return SelectableText.rich(
TextSpan(
text:'',children: data["comment"].split(' ').map<InlineSpan>((word) async {
return word.startsWith('@') && word.length > 1 ?
TextSpan(
text: ' '+ (await context.read<UserDataModel>().fetchUser(word)).displayName,style: TextStyle(color: Colors.blue),): TextSpan(text: ' ' + word);
}).toList()
),textAlign: TextAlign.justify,);
}
可能应该有一个简单的修复,但我找不到
解决方法
显然,当您返回时,您的 snapshot.data
为空。
我会跳过连接状态,只查询 snapshot.hasData
和 snapshot.hasError
以查明数据是否可用。
builder: (BuildContext context,AsyncSnapshot<SelectableText> snapshot) {
if (snapshot.hasData) {
return snapshot.data;
}
// what if snapshot.hasError?
// you don't want to stay in loading mode forever in case of errors
return Center(child: CircularProgressIndicator());
}
也就是说,你应该在这里改进两件事:你的未来应该是你所在州的一个领域。如果您只是在每个构建周期重新创建它,它就会在您不需要重新创建它的情况下重新创建。例如,如果用户将横向模式更改为纵向模式,它将一次又一次地运行,尽管这根本不会改变他们的显示名称。但是您每次都会查询它,因为这就是您设置构建函数的方式。
第二件事是你混合了数据检索和 UI 代码。你的未来是获取数据。但是您将其与创建控件混合在一起。将您的 UI 代码放在构建函数中,并将您的异步数据检索代码移出那里。 那个数据检索代码是您在构建器中应该拥有的未来。
这是实际执行获取数据的异步任务的函数:
Future<Map<String,String>> CreateUserNameMap(String data,UserDataModel model) async {
var userNames = data.split(' ')
.where((word)=> word.startsWith('@') && word.length > 1)
.toSet();
var result = Map<String,String>();
for(var name in userNames) {
var user = await model.fetchUser(name);
result[name] = user.displayName;
}
return result;
}
现在您的 futureBuilder 可能如下所示:
FutureBuilder(
future: gettingUserData,builder: (context,snapshot) {
if (snapshot.hasData) {
return SelectableText.rich(
TextSpan(
text:'',children: data["comment"].split(' ').map<InlineSpan>((word) {
return word.startsWith('@') && word.length > 1 ?
TextSpan(
text: ' ' + snapshot.data[word]
style: TextStyle(color: Colors.blue),) : TextSpan(text: ' ' + word);
}).toList()
),textAlign: TextAlign.justify,);
}
if(snapshot.hasError) {
// you decide...
}
return Center(child: CircularProgressIndicator());
}
其中 gettingUserData
是状态类中的 Future<Map<string,string>>
字段,每当 data['comment']
更改时设置:
gettingUserData = CreateUserNameMap(data['comment'],context.read<UserDataModel>());
一个好地方可能是initState
。但也许您有不同的设置。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。