0

I have built a Flutter application using MobX as my state management and am running into a strange issue at the moment that is only present on Android running in release mode.

I'm not sure if the offender is MobX, Hive or just Flutter in Android itself. However, on this specific page in my app, the Obsever will only display the last entry in the list. The other items are present, but the UI will only show the last index of the list. When I turn my phone landscape, the full content of the list is then visible and the page displays exactly as intended. Is there a way I can force the widgets to re-render in MobX when the page has already loaded?

I have tried downgrading my target SDK to 28, downgrading the gradle version, setting shrinkResources & minifyEnabled to false, enabled proguard. I also have ensured to call this in my main.dart;

WidgetsFlutterBinding.ensureInitialized();

Also attached are the outputs of my flutter doctor.

Again, this issue is only present on Android release build of my app. It works perfectly on iOS & Android on debug.

Any help would be greatly appreciated.

enter image description here

Below is the widget in question that has issues rendering in release mode

    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))),
                            ],
                          ),
                        )
                      ],
                    ),
                  ),
                ),
              ],
            ),
          );
        }
      },
    );
  }
Kizzle
  • 101
  • 3
  • 17

1 Answers1

0

The solution I found was to generate the list directly from the Hive box using a ValueListenableBuilder to listen to the box and add more elements to the list as soon as they arrive in the box. I can only assume there was some kind of race case going on with MobX attempting to gather the elements in the box from Hive and then serve up to the UI layer. I'll attach some sample code below for anyone else who may run into a similar issue.

  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)),
              ),
            );
        },
      );
    });

}

Kizzle
  • 101
  • 3
  • 17