Flutter Android 发布 UI 渲染失败
Posted
技术标签:
【中文标题】Flutter Android 发布 UI 渲染失败【英文标题】:Flutter Android release UI render failure 【发布时间】:2021-08-05 13:35:55 【问题描述】:我已经使用 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,
maxLines: 2,
style: TextStyle(
fontSize: 25,
fontFamily: 'Domus',
color: Color(0xff3c99a0))),
),
],
),
),
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),
fontFamily: 'Aileron',
fontWeight: FontWeight.w700),
);
,
),
),
],
),
Padding(
padding: const EdgeInsets.only(
left: 15.0, top: 0, right: 15),
child: Text(packageDetails.description,
style: TextStyle(
color: Color(0xff1A2E35),
fontFamily: 'Aileron',
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',
style: TextStyle(
color: Color(0xff1A2E35),
fontFamily: 'Aileron',
fontWeight: FontWeight.w700));
else
return Text(
'£$opExtraPrice.toStringAsFixed(2)',
style: TextStyle(
color: Color(0xff1A2E35),
fontFamily: 'Aileron',
fontWeight: FontWeight.w700));
,
),
],
),
),
Padding(
padding: const EdgeInsets.all(15.0),
child: ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: viewModel.customerCars[index]
.optionalExtras.length,
itemBuilder: (context, innerIndex)
var detailedOptionalExtra =
viewModel.getOptinalExtraById(viewModel
.customerCars[index]
.optionalExtras[innerIndex]
.packageItemId);
return Text(
detailedOptionalExtra.name,
style: TextStyle(
color: Color(0xff1A2E35),
fontFamily: 'Aileron',
fontSize: 16,
fontWeight: FontWeight.w300),
);
,
)),
Padding(
padding: const EdgeInsets.all(15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'Total Cost:',
style: TextStyle(
color: Color(0xff1A2E35),
fontFamily: 'Aileron',
fontSize: 16,
fontWeight: FontWeight.w700),
),
Observer(
builder: (context) => Text(
'£$viewModel.currentTotalCost.toStringAsFixed(2)',
style: TextStyle(
color: Color(0xff1A2E35),
fontFamily: 'Aileron',
fontWeight: FontWeight.w700))),
],
),
)
],
),
),
),
],
),
);
,
);
【问题讨论】:
【参考方案1】:我找到的解决方案是使用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)),
),
);
,
);
);
【讨论】:
以上是关于Flutter Android 发布 UI 渲染失败的主要内容,如果未能解决你的问题,请参考以下文章
如何在集成了 Flutter 模块的 Android 应用上运行 UI 测试?