【发布时间】:2022-06-24 18:38:39
【问题描述】:
我正在开发一个带有 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)
经过几天的多次尝试,我完全不知道要检查什么。有没有这方面经验丰富的人可以帮帮我?
附录:
我想知道我的 Stream Builders 是否做错了什么。这是我的代码的缩短版本:
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 和AttendeeList 都使用流。并且每次执行这些小部件中的代码时,都会从数据库中下载大量节点(每个小部件 1500 个)。
一个执行可以如下所示:
PrepareList("London");
另一个执行可能如下所示,在同一屏幕上显示一个新的项目列表:
PrepareList("Manhattan");
我观察到的是:
当我第一次运行PrepareList("London"); 时,需要一些时间(3 到 4 秒)才能看到屏幕上的内容。然后我运行PrepareList("Manhattan");,它也需要大约 3 到 4 秒来显示内容。但是当我再次运行PrepareList("London"); 时,内容会很快出现在屏幕上,大约 1 秒。
为了能够拨打PrepareList(),我需要转到另一个屏幕,这意味着 - 在我的理解中 - 我的流订阅 每次离开屏幕关联到时都会取消上面有 2 个小部件。但是是不是流本身没有被取消,数据仍然在内存中?
我的怀疑:
使用该应用程序时,当我在多个地方(多次)调用PrepareList(...) 时,它会在内存中加载越来越多的数据,并且从不清理它。过了一会儿,应用程序消耗了所有可用内存并通过给出上述错误而崩溃,这告诉我没有任何意义。
并且随着PrepareList(...)在使用应用程序时被执行的次数越来越多,Iphone 7 会发热,我很容易感觉到。我什至用 Iphone 12 进行了测试,它不会像 Iphone 7 那样发热,但也会崩溃。
我什至尝试在两个类中添加如下处理:
@override
void dispose() {
super.dispose();
}
...但它仍然没有帮助。
我的流实现是真的吗? 我怀疑这可能是这次崩溃的根本问题吗?
任何帮助将不胜感激!
附录 2:
我一直在努力...
我以某种方式使用该应用程序,以便多次触发PrepareList("...");。我也观察了 devtools 中的内存使用情况。我可以观察到内存使用量随着时间的推移而增加。这次我遇到了一个新错误,说的是更具体的内容:
[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)。看起来,内存使用量随着时间的推移而增加。为什么用户离开手机屏幕时内存没有释放? (我通过怀疑即使用户移动到另一个屏幕后流仍然占用内存来问这个问题......)
【问题讨论】:
-
正在调查 Flutter v2.16.1、ios v15.1 上的类似问题。您在使用 Firebase 数据库吗?我在错误发生前不久就注意到了一个 Firebase 查询?
-
@Pip 感谢您分享您的评论。是的,我确实使用 Firebase。虽然不可能找到它发生的位置,因为它可能会在应用程序的完全不同的不相关位置崩溃。理解这个错误的含义会很好(例如,这是否意味着内存不足?),这样我就会知道要看什么。
-
你不会得到这样的答案。您需要提供更多关于插件的信息,可能还需要提供设备的完整崩溃日志。
-
@kuhnroyal 如何从设备获取完整的崩溃日志?
标签: firebase flutter dart firebase-realtime-database stream-builder