Flutter Android 发布 UI 渲染失败

Flutter Android release UI render failure

我已经使用 MobX 作为我的状态管理构建了一个 Flutter 应用程序,并且 运行 目前遇到了一个奇怪的问题,该问题仅在 Android 运行 发布模式下出现。

我不确定违规者是 MobX、Hive 还是 Android 本身的 Flutter。但是,在我的应用程序的这个特定页面上,Obsever 只会显示列表中的最后一个条目。其他项目存在,但 UI 将仅显示列表的最后一个索引。当我转动 phone 横向时,列表的全部内容就会显示出来,并且页面会完全按预期显示。当页面已经加载时,有没有一种方法可以强制小部件在 MobX 中重新呈现?

我尝试将我的目标 SDK 降级到 28,降级 gradle 版本,将 shrinkResources & minifyEnabled 设置为 false,启用混淆器。我还确保在 main.dart;

中调用它
WidgetsFlutterBinding.ensureInitialized();

另外附上我的 flutter doctor 的输出。

同样,此问题仅出现在我的应用程序的 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))),
                            ],
                          ),
                        )
                      ],
                    ),
                  ),
                ),
              ],
            ),
          );
        }
      },
    );
  }

我找到的解决方案是直接从 Hive 盒子生成列表,使用 ValueListenableBuilder 来监听盒子并在它们到达盒子时立即将更多元素添加到列表中。我只能假设存在某种竞争情况,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)),
              ),
            );
        },
      );
    });

}