我正在使用 Flutter 开发一个应用程序,并在物理 iOS 设备 (iPhone 7) 上测试该应用程序。
iOS版本是:15.3.1
Flutter版本是:2.10.3
当我测试我的应用程序时,偶尔会发生崩溃。崩溃给出以下错误。它并不总是在同一个地方崩溃,所以我不知道在这里分享什么代码。错误消息本身对我来说并没有说明太多,而且我在网上找不到有关此错误的任何有用信息。
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x443b8000443b8000)
frame #0: 0x0000000198405048 libobjc.A.dylib`objc_msgSend + 8
libobjc.A.dylib`objc_msgSend:
-> 0x198405048 <+8>: ldr x13, [x0]
0x19840504c <+12>: and x16, x13, #0xffffffff8
0x198405050 <+16>: mov x15, x16
0x198405054 <+20>: ldr x11, [x16, #0x10]
Target 0: (Runner) stopped.
Lost connection to device.
Exited (sigterm)
接下来我可以检查什么?
Addendum
我想知道我的 Stream Builder 是否做错了什么。这是我的代码的缩短版本:
class PrepareList extends StatefulWidget {
final String place;
const PrepareList({
Key? key,
required this.place,
}) : super(key: key);
@override
State<PrepareList> createState() =>
_PrepareListState();
}
class _PrepareListState
extends State<PrepareList> {
late final Stream? _listStream;
@override
void initState() {
super.initState();
String dbChild = "events/" + widget.place + "/";
final db = FirebaseDatabase.instance
.ref()
.child(dbChild)
.orderByKey()
.limitToLast(1500);
_listStream = db.onValue;
}
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: _listStream,
builder: (context, AsyncSnapshot<dynamic> dbEvent) {
if (dbEvent.hasError) {
return CircularProgressIndicator();
}
else if (dbEvent.hasData) {
DataSnapshot dataSnapshot = dbEvent.data!.snapshot;
List<EventDetails> placeEventList = [];
if (dataSnapshot.value != null) {
(dataSnapshot.value as Map<dynamic, dynamic>)
.forEach((key, value) {
placeEventList.add(EventDetails.fromRTDB(value));
});
placeEventList
.sort((a, b) => a.dateEST.compareTo(b.dateEST));
return AttendeeList(placeEventList: placeEventList, place: place);
} else {
return PlaceDataNotAvailable(place: widget.place);
}
} else {
return CircularProgressIndicator();
}
});
}
}
class AttendeeList extends StatefulWidget {
final List<EventDetails> placeEventList;
final String place;
const AttendeeList({
Key? key,
required this.placeEventList,
required this.place,
}) : super(key: key);
@override
State<AttendeeList> createState() =>
_AttendeeListState();
}
class _AttendeeListState
extends State<AttendeeList> {
late final Stream? _attendeeListStream;
@override
void initState() {
super.initState();
String dbChild = "attendees/" + widget.place + "/";
final db = FirebaseDatabase.instance
.ref()
.child(dbChild)
.orderByKey()
.limitToLast(1500);
_listStream = db.onValue;
}
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: _attendeeListStream,
builder: (context, AsyncSnapshot<dynamic> dbEvent) {
if (dbEvent.hasError) {
return CircularProgressIndicator();
}
else if (dbEvent.hasData) {
DataSnapshot dataSnapshot = dbEvent.data!.snapshot;
List<AttendeeDetails> attendeeList = [];
if (dataSnapshot.value != null) {
(dataSnapshot.value as Map<dynamic, dynamic>)
.forEach((key, value) {
attendeeList.add(EventDetails.fromRTDB(value));
});
attendeeList
.sort((a, b) => a.dateEST.compareTo(b.dateEST));
return Scaffold(
body: ShowLists(placeEventList, attendeeList);
} else {
return PlaceDataNotAvailable(place: widget.place);
}
} else {
return CircularProgressIndicator();
}
});
}
}
上面的小部件可以在应用程序的生命周期中多次调用。用户通过选择一个来进入此屏幕place
在初始屏幕上,它执行中的代码PrepareList
有状态的小部件,它又调用AttendeeList
有状态的小部件。
我想强调的是,两者PrepareList
and AttendeeList
使用流。每次执行这些小部件中的代码时,都会从数据库下载大量节点(每个小部件 1500 个)。
一次执行可能如下所示:
PrepareList("London");
另一个执行可能如下所示,在同一屏幕上显示新的项目列表:
PrepareList("Manhattan");
我观察到的是:
当我跑步时PrepareList("London");
第一次,需要一些时间(3到4秒)才能看到屏幕上的内容。然后我运行PrepareList("Manhattan");
,也需要大约 3 到 4 秒的时间来显示内容。但当我跑步时PrepareList("London");
同样,内容很快就会出现在屏幕上,大约 1 秒。
为了能够打电话PrepareList()
,我需要转到另一个屏幕,这意味着 - 根据我的理解 - 我的流订阅每次我离开与上面 2 个小部件关联的屏幕时都会被取消。但这是不是这样流本身没有被取消并且数据保留在内存中?
我怀疑的是:使用该应用程序时,正如我所说PrepareList(...)
对于多个位置(多次),它会在内存上加载越来越多的数据,并且永远不会清理它。一段时间后,该应用程序消耗了所有可用内存并通过给出上述错误而崩溃,这告诉我没有任何意义。
And as PrepareList(...)
当使用该应用程序时执行得越来越多,Iphone 7 就会发热,这是我很容易感觉到的。我什至用 iPhone 12 进行了测试,它不像 iPhone 7 那样发热,但也会崩溃。
我什至尝试将 dispose 添加到这两个类中:
@override
void dispose() {
super.dispose();
}
......但仍然没有帮助。
我的流实现是真的吗?我怀疑这可能是这次崩溃的根本问题吗?
附录2
我一直在努力。我以这样的方式使用该应用程序PrepareList("...");
被触发多次。我也在开发工具中观察了内存使用情况。我可以观察到内存使用量随着时间的推移而增加。这次我遇到了一个新错误,说了一些更具体的内容:
[ServicesDaemonManager] interruptionHandler is called. -[FontServicesDaemonManager connection]_block_invoke
[tcp] tcp_input [C17.1.1:3] flags=[R] seq=3749683210, ack=0, win=0 state=LAST_ACK rcv_nxt=3749683210, snd_una=3584722489
[tcp] tcp_input [C17.1.1:3] flags=[R] seq=3749683210, ack=0, win=0 state=CLOSED rcv_nxt=3749683210, snd_una=3584722489
* thread #46, name = 'DartWorker', stop reason = EXC_RESOURCE RESOURCE_TYPE_MEMORY (limit=1450 MB, unused=0x0)
frame #0: 0x0000000108ef4d0c Flutter`dart::CompilerPass_TypePropagation::DoBody(dart::CompilerPassState*) const + 1644
Flutter`dart::CompilerPass_TypePropagation::DoBody:
-> 0x108ef4d0c <+1644>: str xzr, [x20, x28, lsl #3]
0x108ef4d10 <+1648>: ldr x8, [x22, #0x48]
0x108ef4d14 <+1652>: cmp x24, x8
0x108ef4d18 <+1656>: b.ge 0x108ef4d84 ; <+1764>
Target 0: (Runner) stopped.
Lost connection to device.
这次,它说EXC_RESOURCE RESOURCE_TYPE_MEMORY (limit=1450 MB, unused=0x0)
。看起来,内存使用量随着时间的推移而增加。为什么当用户离开手机屏幕时内存没有释放? (我通过怀疑即使用户移动到另一个屏幕后流仍然占用内存来问这个问题......)