flutterdartflutter-provider

Flutter Provider: notifyListeners does not update AlertDialog widget


I'm using Provider to provide some data to my screen and an alert dialog. Knowing that AlertDialog is scooped outside the widget tree, I added a ChangeNotifierProvider as a wrapper widget of that dialog. But still, the UI is not changing even though I made sure the values are updated in the provider state.

Code Snippet:

showTextDialog(BuildContext context) {
  final myModel = Provider.of<ServicesProvider>(context, listen: false);
  return showDialog(
    context: context,
    builder: (_) => ChangeNotifierProvider.value(
      value: myModel,
      child: AlertDialog(
        content: IntrinsicHeight(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Row(
                children: [
                  Radio(
                    value: '0',
                    groupValue: myModel.paymentMethod,
                    onChanged: (value) => myModel.setPaymentMethod('0'),
                    activeColor: ColorResources.PRIMARY_COLOR,
                    toggleable: true,
                  ),
                  SizedBox(width: responsiveWidth(5)),
                  Text("Radio Button 1"),
                ],
              ),
              SizedBox(height: responsiveHeight(10)),
              Row(
                children: [
                  Radio(
                    value: '1',
                    groupValue: myModel.paymentMethod,
                    onChanged: (value) => myModel.setPaymentMethod('1'),
                    activeColor: ColorResources.PRIMARY_COLOR,
                    toggleable: true,
                  ),
                  SizedBox(width: responsiveWidth(5)),
                  Flexible(child: Text("Radio Button 2")),
                ],
              ),
            ],
          ),
        ),
      ),
    ),
  );
}

Thanks for your help.


Solution

  • The main idea behind your problem is that you do not subscribe to the changes of your ServicesProvider. You can replace Provider.of<ServicesProvider>(context, listen: false); with context.read<ServicesProvider>(); that is a more concise syntax using extension methods.

    Based on the Provider documentation:

    context.read<T>(), which returns T without listening to it. <...> It's worth noting that context.read<T>() won't make a widget rebuild when the value changes and it cannot be called inside StatelessWidget.build/State.build. On the other hand, it can be freely called outside of these methods.

    What you have done already with final myModel = Provider.of<ServicesProvider>(context, listen: false); is that you only retrieved the reference to ServicesProvider. However, this way you do not subscribe to the changes inside the model - this is exactly what the documentation explains.

    To resolve this, you can move the AlertDialog into a separate widget, e.g. MyDialog. There is a practical reason - it's just easier to understand that now you are not using the same context and you should access the re-provided ServicesProvider model. Now, by using context.watch<ServicesProvider>() (you could use the Consumer widget as well if you would like to), you can subscribe to the changes of your model. Thus, when there is a change for the paymentMethod value inside the model (you can do it by calling the setPaymentMethod() method on model), it triggers UI rebuild (notifyListeners() does its work) and you get the expected output.

    You could find the recreated and resolved issue here.