问题描述
我使用 MobX 作为我的状态管理构建了一个 Flutter 应用程序,目前遇到了一个奇怪的问题,该问题仅存在于以发布模式运行的 Android 上。
我不确定冒犯者是 MobX、Hive 还是 Android 本身的 Flutter。但是,在我的应用程序的这个特定页面上,观察者只会显示列表中的最后一个条目。其他项目存在,但 UI 将仅显示列表的最后一个索引。当我转动手机横向时,可以看到列表的全部内容,并且页面完全按预期显示。当页面已经加载时,有没有办法强制小部件在 MobX 中重新渲染?
我尝试将我的目标 SDK 降级到 28,降级 gradle 版本,将 shrinkResources & minifyEnabled 设置为 false,启用 proguard。我还确保在我的 main.dart 中调用它;
WidgetsFlutterBinding.ensureInitialized();
还附上了我的颤振医生的输出。
同样,此问题仅存在于我的应用的 Android 版本版本中。它在调试时在 iOS 和 Android 上完美运行。
任何帮助将不胜感激。
下面是有问题的小部件在发布模式下呈现问题
Widget _carPackageList() {
return ListView.builder(
physics: NeverScrollableScrollPhysics(),shrinkWrap: true,itemCount: viewmodel.customerCars.length,itemBuilder: (context,index) => _carListItem(index));
}
Widget _carListItem(index) {
var packageDetails = viewmodel.getDetailBookingById(
viewmodel.customerCars[index].packageGroupId);
return Observer(
builder: (context) {
if (viewmodel.isLoading) {
return CustomProgressIndiactor();
} else {
return Padding(
padding: const EdgeInsets.all(8.0),child: Column(
crossAxisAlignment: CrossAxisAlignment.start,children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,children: [
Flexible(
child: Column(
children: [
Text(
viewmodel.customerCars[index].makeAndModel,maxLines: 2,style: TextStyle(
fontSize: 25,fontFamily: 'Domus',color: Color(0xff3c99a0))),],),IconButton(
icon: Icon(Icons.highlight_remove,color: Colors.black),onpressed: () {
viewmodel.removeCustomerCar(index);
viewmodel.customerCars.removeAt(index);
})
],Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0),child: Container(
width: double.infinity,child: Column(
mainAxisSize: MainAxisSize.min,crossAxisAlignment: CrossAxisAlignment.start,children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,children: [
Flexible(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(15.0),child: Text(packageDetails.name,overflow: TextOverflow.ellipsis,style: TextStyle(
fontSize: 25,Padding(
padding: const EdgeInsets.all(15.0),child: Observer(
builder: (_) {
var groupPrice =
viewmodel.calculateCarCost(
viewmodel.customerCars[index],viewmodel.customerCars[index]
.packageGroupId);
if (groupPrice == null) {
return Text('£0.00',style: TextStyle(
color: Color(0xff1A2E35),fontFamily: 'Aileron',fontWeight: FontWeight.w700));
} else {
return Text(
'£${groupPrice.toStringAsFixed(2)}',style: TextStyle(
color: Color(0xff1A2E35),fontWeight: FontWeight.w700),);
}
},Padding(
padding: const EdgeInsets.only(
left: 15.0,top: 0,right: 15),child: Text(packageDetails.description,style: TextStyle(
color: Color(0xff1A2E35),fontSize: 16,fontWeight: FontWeight.w300)),Padding(
padding: const EdgeInsets.all(15.0),child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,children: [
Text('Optional Extras',style: GoogleFonts.lato(
fontSize: 16,color: Colors.black,fontWeight: FontWeight.bold)),Observer(
builder: (_) {
var opExtraPrice = viewmodel
.calculateOptionalExtrasPrice(viewmodel
.customerCars[index]
.optionalExtras);
if (opExtraPrice == null) {
return Text('£0.00',fontWeight: FontWeight.w700));
} else {
return Text(
'£${opExtraPrice.toStringAsFixed(2)}',fontWeight: FontWeight.w700));
}
},Padding(
padding: const EdgeInsets.all(15.0),child: ListView.builder(
shrinkWrap: true,physics: NeverScrollableScrollPhysics(),itemCount: viewmodel.customerCars[index]
.optionalExtras.length,innerIndex) {
var detailedOptionalExtra =
viewmodel.getoptinalExtraById(viewmodel
.customerCars[index]
.optionalExtras[innerIndex]
.packageItemId);
return Text(
detailedOptionalExtra.name,style: TextStyle(
color: Color(0xff1A2E35),fontWeight: FontWeight.w300),);
},)),children: <Widget>[
Text(
'Total Cost:',style: TextStyle(
color: Color(0xff1A2E35),Observer(
builder: (context) => Text(
'£${viewmodel.currentTotalCost.toStringAsFixed(2)}',fontWeight: FontWeight.w700))),)
],);
}
},);
}
解决方法
我找到的解决方案是使用 ValueListenableBuilder
直接从 Hive 框生成列表以侦听框并在更多元素到达框后立即将其添加到列表中。我只能假设 MobX 试图从 Hive 收集框中的元素,然后提供给 UI 层,这是一种竞争情况。我会在下面附上一些示例代码,供其他可能遇到类似问题的人使用。
Widget buildList() {
var _box = Hive.box("myBox").listenable();
return ValueListenableBuilder(
valueListenable: _box,builder: (context,box,widget) {
return ListView.builder(
itemCount: box.length,itemBuilder: (context,index) {
return Container(
decoration: BoxDecoration(
border: Border(bottom: BorderSide(width: 0.1))),child: ListTile(
title: Text(Hive.box("myBox").getAt(index)),),);
},);
});
}