In Flutter MaterialApp, using Provider inside LocaleResolutionCallback has an error - flutter

In my flutter project, I selected riverpod_hook for DI.
In order to change the language setting of the application according to the language setting of the mobile device, I wrote the code as follows.
// app.dart
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
class Application extends ConsumerWidget {
const Application({Key? key}) : super(key: key);
#override
Widget build(BuildContext context, WidgetRef ref) {
return MaterialApp(
theme: defaultTheme,
localizationsDelegates: Resource.localizationsDelegates,
supportedLocales: Resource.supportedLocales,
localeResolutionCallback: (Locale? locale, Iterable<Locale> supportedLocales) {
if (supportedLocales.any((element) => locale?.languageCode.contains(element.toString()) == true)) {
ref.watch(localeCodeProvider.notifier).state = locale!.languageCode;
return locale;
}
return const Locale('ko', '');
},
routes: {
homePageRoutes: (_) => const HomePage(),
detailPageRoutes: (_) => const DetailPage(),
},
);
}
}
import 'package:hooks_riverpod/hooks_riverpod.dart';
final localeCodeProvider = StateProvider<String>((ref) => 'en');
When I run this code, this error was occurred.
E/flutter ( 3747): [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: Tried to modify a provider while the widget tree was building.
E/flutter ( 3747): If you are encountering this error, chances are you tried to modify a provider
E/flutter ( 3747): in a widget life-cycle, such as but not limited to:
E/flutter ( 3747): - build
E/flutter ( 3747): - initState
E/flutter ( 3747): - dispose
E/flutter ( 3747): - didUpdateWidget
E/flutter ( 3747): - didChangeDepedencies
E/flutter ( 3747):
E/flutter ( 3747): Modifying a provider inside those life-cycles is not allowed, as it could
E/flutter ( 3747): lead to an inconsistent UI state. For example, two widgets could listen to the
E/flutter ( 3747): same provider, but incorrectly receive different states.
E/flutter ( 3747):
E/flutter ( 3747):
E/flutter ( 3747): To fix this problem, you have one of two solutions:
E/flutter ( 3747): - (preferred) Move the logic for modifying your provider outside of a widget
E/flutter ( 3747): life-cycle. For example, maybe you could update your provider inside a button's
E/flutter ( 3747): onPressed instead.
E/flutter ( 3747):
E/flutter ( 3747): - Delay your modification, such as by encasuplating the modification
E/flutter ( 3747): in a `Future(() {...})`.
E/flutter ( 3747): This will perform your upddate after the widget tree is done building.
I can see from the error message that the error occurred because the provider watch was used inside the build function.
However, I unwillingly need to utilize that localeResolutionCallback attribute because I want to set the language setting value of the mobile device and set the language across the application.
In this situation, could I get an appropriate solution on how to use the provider?

Try if calling WidgetsBinding.instance.addPostFrameCallback would work, somethign like this:
if (supportedLocales.any((element) => locale?.languageCode.contains(element.toString()) == true)) {
WidgetsBinding.instance.addPostFrameCallback((_) {
ref.watch(localeCodeProvider.notifier).state =
locale!.languageCode;
});
return locale;
}
What it does - it allows your build to complete; and then changes the provider - which will most likely call another build.

Related

Unhandled Exception: Null check operator used on a null value in flutter

I hope you are well, I will give you a bit of context about my problem...
I really don't know why this error happens and I've seen many similar publications but they haven't worked for me.
I'm new to flutter and I'm working on an app, but when the user wants to log out, the app crashes and shows the following error:
E/flutter (12659): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Null check operator used on a null value
E/flutter (12659): #0 StatefulElement.state
package:flutter/…/widgets/framework.dart:4999
E/flutter (12659): #1 Navigator.of
package:flutter/…/widgets/navigator.dart:2543
E/flutter (12659): #2 Navigator.pushReplacement
package:flutter/…/widgets/navigator.dart:2105
E/flutter (12659): #3 MainCoordinator.logoutNavigation
package:domicilios/…/MainCoordinator/MainCoordinator.dart:62
E/flutter (12659): #4 UserActions.signOut.<anonymous closure>.<anonymous closure>
package:domicilios/…/View/ProfileTab.dart:222
E/flutter (12659): <asynchronous suspension>
This is the code that generates this error, I hope you can help me, thank you very much for your attention.
this is the class:
extension UserActions on _ProfileTabState {
void signOut(BuildContext context) {
AlertView.showAlertDialog(
model: AlertViewModel(
context,
const AssetImage('assets/logout.png'),
'Cierre de sesión en curso',
"¿Desear salir de la sesión actual?",
'Cerrar sesión',
"Cancelar", () {
_profileTabViewModel
.signOut()
.then((value) => coordinator.logoutNavigation(context: context));
}, () {
Navigator.pop(context);
}));
}
}
That's how I call it in the code:
onTap: () => signOut(context),
This is most likely due to the widget being unmounted before navigating.
You can check if the widget is mounted before navigating.
if (mounted) {
_profileTabViewModel.signOut().then((value) {
if (mounted) {
coordinator.logoutNavigation(context: context);
}
});
}
Also,
if(mounted){
Navigator.pop(context);
}

Flutter platform player already exists just audio

So happy with the just audio flutter package from Ryan Heise for our radio app. Best package I know.
We have no problems with iOS, but on Android now some strange behavior, especially on Android 10. I'm also using the audio service and audio session packages to play the radio as background music. When the user hits play, no music is playing and error in the console:
Error:
E/flutter ( 6721): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: PlatformException(Platform player 6f26b522-c6c3-4226-be22-80f9d15dfc2c already exists, null, null, null)
E/flutter ( 6721): #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:653:7)
E/flutter ( 6721): #1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:296:18)
E/flutter ( 6721):
E/flutter ( 6721): #2 MethodChannelJustAudio.init (package:just_audio_platform_interface/method_channel_just_audio.dart:13:5)
E/flutter ( 6721):
E/flutter ( 6721): #3 AudioPlayer._setPlatformActive.setPlatform (package:just_audio/just_audio.dart:1255:13)
E/flutter ( 6721):
Code in main.dart:
Future<void> main() async {
// initialise audio_service with our audio_handler
myAudioHandler = await AudioService.init(
builder: () => MyAudioHandler(),
config: const AudioServiceConfig(
androidNotificationChannelId: 'com.ryanheise.myapp.channel.audio',
androidNotificationChannelName: 'Audio playback',
androidNotificationOngoing: true,
),
);
Code in audio_handler.dart:
Future<void> _loadRadio() async {
final session = await AudioSession.instance;
await session.configure(const AudioSessionConfiguration.music());
// Try to load the radio from the source and catch any errors.
try {
await _player.setAudioSource(AudioSource.uri(
Uri.parse([stream_address])));
} catch (e) {
print("Error loading audio source: $e");
}
}
What does this error mean? And why is it only giving problems on some Android versions?
On Android 12 this is not happening all the time.
On Android 10 this is happening a lot.
We have several user complaints with the Android platform.
The error was coming from a myAudioHandler.stop command inside an internet connection checker function. When removed, everything worked again with all our Android users. This code was for testing purposes, and shouldn't be there. I hope this helps others with this error. Thanks for your help.

How can I do contextless navigation in order to move to a maintenance screen in Flutter?

I have a Maintenance controller, that initializez an observable variable, and whenever that variable is true, it navigates to a maintenance screen, and when the variable gets set to false it navigates back as follows:
class MaintenanceController extends GetxController {
RxBool isMaintenance = false.obs;
#override
onInit() {
super.onInit();
ever(
isMaintenance,
(_) => {
if (isMaintenance.value) {Get.offNamed(Routes.maintenance)} else {Get.offNamed(Routes.splash)}
});
}
}
Everything works fine, but I get the following exception in the logs:
flutter: You are trying to use contextless navigation without
a GetMaterialApp or Get.key.
If you are testing your app, you can use:
[Get.testMode = true], or if you are running your app on
a physical device or emulator, you must exchange your [MaterialApp]
for a [GetMaterialApp].
flutter:
#0 GetNavigation.global (package:get/get_navigation/src/extension_navigation.dart:1094:7)
#1 GetNavigation.offNamed (package:get/get_navigation/src/extension_navigation.dart:629:12)
#2 MaintenanceController.onInit.<anonymous closure> (package:n_app/src/screens/maintenance/maintenance_controller.dart:17:85)
#3 ever.<anonymous closure> (package:get/get_rx/src/rx_workers/rx_workers.dart:69:44)
#4 GetStream._notifyData (package:get/get_rx/src/rx_stream/get_stream.dart:47:21)
#5 GetStream.add (package:get/get_rx/src/rx_stream/get_stream.dart:97:5)
#6 RxObjectMixin.value= (package:get/get_rx/src/rx_types/rx_core/rx_impl.dart:105:13)
#7 MaintenanceController.subscribe.<anonymous closure> (package:n_app/src/screens/maintenance/maintenance_controller.dart:29:21)
#8 _rootRunUnary (dart:async/zone.dart:1434:47)
#9 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
#10 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1244:7)
#11 _Bufferi<…>
flutter: ----------------------------------------------------
app.dart:
GetMaterialApp(
debugShowCheckedModeBanner: false,
locale: Get.find<LocalizationController>().deviceLocale,
getPages: Routes.routes,
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
unknownRoute: Routes.getNotFound,
initialRoute: GetPlatform.isWeb ? Routes.initial : Routes.splash,
theme: Get.find<ThemeController>().themeData,
navigatorKey: NavigationService.navigatorKey,
);
I tried to add the navigatorKey: Get.key and use navigatorKey.currentState!.pushNamed(routeName); to navigate, but the currentState is always null. Any advice?
You have to use GetMaterialApp instead of MaterialApp for the contextless navigation to work in GetX.
Replace
MaterialApp(home: somePage());
with
GetMaterialApp(home: somePage());
Adding navigatorKey: Get.key to the GetMaterialApp and continuing to use Get.offNamed(...) instead of navigatorKey.currentState!.pushNamed(routeName); worked.

Flutter md link not loading md file

I am using the flutter_markdown widget to display help info in my app.
Inside an md file I am using the link to another md file. Both md files are defined in the 'assets' list in the pubspec.yml file
### [Overview](resource:asset/doc/overview.md) / Match Screen ###
Then I'm using the 'onTapLink' event handler to capture the users tap on the link to reset the markup widget to display the new md file like...
Future<String> _getData(String aFileName) async{
return rootBundle.loadString(aFileName);
}
#override
Widget build(BuildContext context) {
// get
return Scaffold(
appBar: AppBar(title: Text('Help')),
body: FutureBuilder<String>(
future: _dataFuture,
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
if (snapshot.hasData) {
return Markdown(data: snapshot.data!, onTapLink: (text,href,title) {
setState(() {
_dataFuture = _getData(href!);
});
},);
}
return Center(
child: CircularProgressIndicator(),
);
}),
);
}
However, the onTapLnk code is causing an exception where it can't load the md file name passed in 'hef'
E/flutter ( 7261): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: Unable to load asset: resource:asset/doc/overview.md
E/flutter ( 7261): #0 PlatformAssetBundle.load (package:flutter/src/services/asset_bundle.dart:237:7)
E/flutter ( 7261): <asynchronous suspension>
E/flutter ( 7261): #1 AssetBundle.loadString (package:flutter/src/services/asset_bundle.dart:72:27)
E/flutter ( 7261): <asynchronous suspension>
E/flutter ( 7261):
Any suggestions?
Through testing I can separately display both md files, so its nothing to do with faulty asset definition in the pubspec.yml file.
Solved it
The link definition in the md file should be
### [Overview](asset/doc/overview.md) / Match Screen ###
not
### [Overview](resource:asset/doc/overview.md) / Match Screen ###

Null check operator error in Flutter application

I am developing a Flutter app that implements OpenID authentication. I am getting the following error in one of the flutter libraries I am using (library https://pub.dev/packages/openid_client). The error is as follows:
E/flutter (14084): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled ExceptionNull check operator used on a null value
E/flutter (14084): #0 new Flow._
package:solidauth/…/src/openid.dart:344
E/flutter (14084): #1 new Flow.authorizationCode
package:solidauth/…/src/openid.dart:361
E/flutter (14084): #2 new Authenticator
package:solidauth/openid/openid_client_io.dart:23
E/flutter (14084): #3 AppLogin.authenticate1
package:solidauth/main.dart:873
E/flutter (14084): <asynchronous suspension>
E/flutter (14084): #4 AppLogin.build.<anonymous closure>
package:solidauth/main.dart:574
E/flutter (14084): <asynchronous suspension>
The piece of code that I am getting the error is the following:
class Authenticator {
final Flow flow;
final Function(String url) urlLancher;
final int port;
Authenticator(Client? client,
{this.port = 3000,
this.urlLancher = _runBrowser,
Iterable<String> scopes = const [],
Uri? redirectUri})
: flow = redirectUri == null
? Flow.authorizationCodeWithPKCE(client)
: Flow.authorizationCode(client)
..scopes.addAll(scopes)
..redirectUri = redirectUri ?? Uri.parse('http://localhost:$port/');
... some other functions ...
}
The error is coming from the above class constructor when I call it like the following. But I don't see any obvious errors in there. Not sure what I am doing wrong here.
// create an authenticator
var authenticator = new Authenticator(client,
scopes: scopes,
port: 4000,
urlLancher: urlLauncher,
redirectUri: Uri.parse(redirUrl));
I think the issue comes from this line in the class Flow because the client is null, so the null check ! will throw that error.
Flow._(this.type, this.responseType, this.client, {String? state})
: state = state ?? _randomString(20) {
var scopes = client!.issuer!.metadata.scopesSupported; <-- This line
for (var s in const ['openid', 'profile', 'email']) {
if (scopes!.contains(s)) {
this.scopes.add(s);
break;
}
}