Home > Enterprise >  Flutter: My notifyListeners() doesn't work, but only in the release apk
Flutter: My notifyListeners() doesn't work, but only in the release apk

Time:02-04

I have a page that shows a loading while making my API call, and once the call is done it shows the received data.

On debugger everything works correctly, but when I create the apk with 'flutter build apk', and download it, the loading remains indefinitely.

I also put a showDialog at the end of my Provider function that makes the API call (I put this showDialog just below notifyListeners().

I can't understand why in debug it works and in release it doesn't.

(This notifyListeners thing not working just does it for every API call I make)

This is the code of the provider function that makes the api call:

Future<void> getUserSites(context) async {
     _userSites.clear();
     isLoading = true;
     notifyListeners(); 
     try { 
       final response = await NetworkService.call( 
           url: '/api/structure/Sites', 
           method: Method.Get, 
           context: context) as List<dynamic>;      
     for (var i = 0; i < response.length; i  ) {
        _userSites.add(Sites.fromJson(response.elementAt(i)));
      }

      if (defaultSite == null) {
        if (SimplePreferences.getDefaultSite() == null) {
          defaultSite = _userSites.isNotEmpty ? _userSites.first : null;
          if (defaultSite != null) {
            SimplePreferences.setDefaultSite(defaultSite!.id);
          }
        } else {
          defaultSite = _userSites.firstWhere(
              (element) => element.id == SimplePreferences.getDefaultSite()!);
        }
      }

  
    } catch (e) {
      inspect(e);
      if (SimplePreferences.getToken() != null) {
        showDialog(
          context: context,
          builder: (ctx) => AlertDialog(
            title: const Text('General Error'),
            content: Text(e.toString()),
            actions: [
              TextButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: const Text(
                  'Ok',
                ),
              )
            ],
          ),
        );
      }
      // throw e;
    }
    isLoading = false;
    notifyListeners();
    showDialog(
          context: context,
          builder: (ctx) => AlertDialog(
            title: const Text('getUserSites done!'),
            content: Text(_userSites.toString()),
            actions: [
              TextButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: const Text(
                  'Ok',
                ),
              )
            ],
          ),
        );
  }

this is the Home page code:

class HomePageScreen extends StatelessWidget { const HomePageScreen({super.key}); static const String routeName = '/';

@override Widget build(BuildContext context) { log('New Page: Home Page'); final provider = Provider.of<MyManager>(context);
return provider.isLoading ? const Center(
        child: CircularProgressIndicator(),
      )
    : SingleChildScrollView(
        physics: const BouncingScrollPhysics(),
        child: Container(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              MainButton(
                onTap: () async {
                    Navigator.of(context)
                      .pushNamed(ShowPatrolScreen.routeName);
                      await provider.getPatrol(context);
                },
                icon: Icons.home,
                title: 'ShowPatrol',
              ),
              printSito(provider.defaultSite?.description ?? 'Nessun Sito', context),
              PrintRequestZ(
                showCompleted: false,
              ),
            ],
          ),
        ),
      );
}

Widget printSito(String name, context) { .... //pass context for Navigator and Theme } } `

this is the main page:

...
final myScreens = [
     const HomePageScreen(),
     ...
];

@override
void initState() {
    // TODO: implement initState
    super.initState();
    print('token: ${SimplePreferences.getToken()}');
    if (SimplePreferences.getToken() == null){
       Navigator.of(context).pushReplacementNamed('/Auth');
    }
    var provider = Provider.of<MyManager>(context, listen: false);
    provider.setAll(context); //this function calls all my API calls, but for testing, I commented out all other functions and kept only the one written above
}

@override
Widget build(BuildContext context) {
    var provider = Provider.of<MyManager>(context);
    return Scaffold(
      appBar: const MyAppBar(title: 'Ronda',canGoBack: false,),
      body: myScreens[currentPage],
      bottomNavigationBar: ...
    ),
}

Thanks in advance!

CodePudding user response:

after some research i found the solution. You have to use WidgetsBinding.instance.addPostFrameCallback in the parent component. So my home page now looks like this:

@override
    void initState() {
        // TODO: implement initState
        super.initState();
        print('token: ${SimplePreferences.getToken()}');
        if (SimplePreferences.getToken() == null){
           Navigator.of(context).pushReplacementNamed('/Auth');
        }
        WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
           var provider = Provider.of<MyManager>(context, listen: false);
           provider.setAll(context); //this function calls all my API calls, but for testing, I commented out all other functions and kept only the one written above
        });
    }

I don't quite understand why though. If someone could explain it to me, I'd be very happy

CodePudding user response:

Use Consumer to access the Provider's Variable

return Consumer<YourProviderName>(builder : (context, value, child){
return value.isLoading? const Center(
    child: CircularProgressIndicator(),
  ):YourWidget(),
});
  • Related