file - Flutter/Dart:同步读取资产文件夹中的文件
问题描述
我正在尝试读取资产文件夹中的 JSON 文件并将其反序列化为对象。
String fromJson = await rootBundle.loadString('assets/File.json');
反序列化函数是异步的,因此它甚至在实际读取 JSON 文件并对其进行反序列化之前就返回。这就是为什么从项目的不同位置对该反序列化函数进行多次调用的原因。
所有异步调用都在执行第一个等待调用之前排队,即。await rootBundle.loadString('assets/File.json');
所以文件被多次读取。
有没有办法等待文件读取或等到反序列化发生然后返回给反序列化函数的调用者?或同步方式读取资产文件夹中的文件?我希望文件只读取一次并等待反序列化发生。
解决方案
一般来说,异步读取文件根本不成问题,实际上是推荐的。您不想在等待文件加载和解析时阻塞 UI。
因此,这意味着您的代码中可能存在导致此问题的小错误。由于您没有列出任何代码,因此我无法真正指出问题所在,但我确实有一个我一直在使用的示例,它可能会对您有所帮助。
在我的示例应用程序(您可以在此处找到)中,我使用以下 JSON 文件(实际文件更大,但这给了您一个想法):
地方.json
{
"html_attributions": [],
"results": [
{
"geometry": {
"location": {
"lat": 52.221525,
"lng": 6.895323999999999
},
"viewport": {
"northeast": {
"lat": 52.2231135302915,
"lng": 6.897867100000001
},
"southwest": {
"lat": 52.2204155697085,
"lng": 6.894476299999999
}
}
},
"icon": "https://maps.gstatic.com/mapfiles/place_api/icons/restaurant-71.png",
"id": "6e274492c5dfc4100a68d47e70d8f69e1bbef40a",
"name": "Fellini Enschede",
"opening_hours": {
"open_now": true
},
"photos": [
{
"height": 3024,
"html_attributions": [
"<a href=\"https://maps.google.com/maps/contrib/109213220123895357242/photos\">Martijn Hoppenbrouwer</a>"
],
"photo_reference": "CmRaAAAAPhSAiB4-VuS-AmUdRxjBUIooQJg68zdQyLRmPJGOB7G_2xh9deq3lcI9ChPnlaTZPmQtUQ_uBqWenNLif0Okqqr5ErAGPBlhoIpcbW6iBt0Uto1qjOjRPuWTRrrL_imlEhDjC25hFY3jKzMU04ZbXUaqGhQh13kxVLaYj-aNxDnsqWfRvfWFBA",
"width": 4032
}
],
"place_id": "ChIJ8XcydnMUuEcRCFdOhmTnLsY",
"plus_code": {
"compound_code": "6VCW+J4 Enschede, Netherlands",
"global_code": "9F486VCW+J4"
},
"rating": 4.1,
"reference": "CmRSAAAAtmshr7ZCjO5X5Zb8ZHNGgek6CzPUBXHBEtP7AR_A8vg10GMpcMCdk_S1Y141Nv5G3f7ed9XFPaSjU6aR_lHoJ6PwNx3lQL7HJf9ai9G2aExbs5KHuwacwTqUV3ocI1RkEhDWe_4cklgqwe94iyEOg4fNGhSZL88S4ZAde2kWm0VAwm8gObCCjg",
"scope": "GOOGLE",
"types": [
"night_club",
"bar",
"restaurant",
"food",
"point_of_interest",
"establishment"
],
"vicinity": "2, Bolwerkstraat, Enschede"
},
{
"geometry": {
"location": {
"lat": 52.22302359999999,
"lng": 6.893403099999998
},
"viewport": {
"northeast": {
"lat": 52.22446798029149,
"lng": 6.894722280291502
},
"southwest": {
"lat": 52.22177001970849,
"lng": 6.892024319708497
}
}
},
"icon": "https://maps.gstatic.com/mapfiles/place_api/icons/generic_business-71.png",
"id": "a18ff7853e5f6eb545fcb93fd55c85cf915bd301",
"name": "'T Bölke",
"photos": [
{
"height": 1152,
"html_attributions": [
"<a href=\"https://maps.google.com/maps/contrib/115418315198000399419/photos\">'t Bölke</a>"
],
"photo_reference": "CmRaAAAAhRaUOljchj6XFtlC7sB-93l4pfcEMTClAG6pZbPkE4KQ64Y9kPY0cAZ6uozFJdD_aB7BHPfIbhY2EU-47b8v_lWjaZcaQX_YIhh1Hqbz9tMCv-brLfxYzykbpfYMVaa2EhD_9RqnDMDDYjzR_lJvYW_UGhQi4dnTzDTgIiaRHNVrlmfv28qRvw",
"width": 2048
}
],
"place_id": "ChIJX2MAvHQUuEcRY9HmmyKX1oI",
"plus_code": {
"compound_code": "6VFV+69 Enschede, Netherlands",
"global_code": "9F486VFV+69"
},
"rating": 4.1,
"reference": "CmRSAAAAZ-3uQbzsSLjQRshhJ9L6J7iOOMV2T7HL-ELqrufGKXflCbVHaEDD3-eNoAvVsF0k4muHAQT-rQaf-bYPFuy3BafMyLzMnscR1cTuCVwpLvo-Gh9O62PJmhMtSqbcJvoCEhDVHVVCEIxrmEhHY96ucRlHGhTAU1zn9KcPxRsZslAvinU1mBmtSQ",
"scope": "GOOGLE",
"types": [
"night_club",
"bar",
"point_of_interest",
"establishment"
],
"vicinity": "Molenstraat 6-8, Enschede"
}
]
}
接下来我有一个帮助 Dart 文件,它定义了Place
类并包含一个方法,该方法将读取文件并将 JSON 项转换为Place
类的实例,如下所示:
地方.dart
import 'dart:async';
import 'dart:convert';
import 'package:flutter/services.dart';
class Place {
final String name;
final double rating;
final String address;
Place.fromJson(Map jsonMap) :
name = jsonMap['name'],
rating = jsonMap['rating']?.toDouble() ?? -1.0,
address = jsonMap['vicinity'];
String toString() => 'Club: $name';
}
Future<Stream<Place>> getPlaces() async {
return new Stream.fromFuture(rootBundle.loadString('assets/places.json'))
.transform(json.decoder)
.expand((jsonBody) => (jsonBody as Map)['results'])
.map((jsonPlace) => new Place.fromJson(jsonPlace));
}
最后,我有一个非常简单的 UI,它将调用该getPlaces
方法并在 a 中显示所有记录ListView
:
主要.dart
import 'package:flutter/material.dart';
import 'places.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Slurp',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Slurp'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<Place> _places = <Place>[];
@override
void initState() {
super.initState();
listenForPlaces();
}
void listenForPlaces() async {
var stream = await getPlaces();
stream.listen(
(place) =>
setState(
() => _places.add(place)
)
);
}
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new Center(
child: new ListView(
children: _places.map((place) => new PlaceWidget(place)).toList(),
),
),
);
}
}
class PlaceWidget extends StatelessWidget {
final Place place;
PlaceWidget(this.place);
@override
Widget build(BuildContext context) {
var ratingColor = Color.lerp(Colors.red, Colors.green, place.rating / 5);
var listTile = new ListTile(
leading: new CircleAvatar(
child: new Text(place.rating.toString()),
backgroundColor: ratingColor,
),
title: new Text(place.name),
subtitle: new Text(place.address),
);
return new Dismissible(
key: new Key(place.name),
background: new Container(color: Colors.green),
secondaryBackground: new Container(color: Colors.red),
onDismissed: (dir) {
if(dir == DismissDirection.startToEnd) {
print("You liked ${place.name}");
} else {
print("You didn't like ${place.name}");
}
},
child: listTile,
);
}
}
推荐阅读
- azure - 使用 AAD 的 ROPC 流程的用户登录
- java - 如何在 Java 中读取整行输入而不跳过它(scanner.next())
- rest - Alfresco - 用公司主页替换/站点?
- python - how I can fix this error? TypeError: list indices must be integers or slices, not str
- spring-boot - 如何使用 swagger OpenAPI 注释将描述设置为字段
- java - 如何在 Java 中声明任何类类型的变量或对象
- javascript - 如何将时间设置为始终:00:00:00?
- python-3.x - 是否可以将句子拆分为字符串列表并将同一行中的字符串列表大写?
- flutter - 为 Flutter 开发人员制作 UI 的最快方法?
- javascript - nodejs url.resolve 函数有什么替代品吗?