OnNavigatedTo only gets called when using NavigationService - mvvm

We have a MVVM app build with Xamarin.Forms and Prism.Forms. The OnNavigatedTo and OnNavigatedFrom (from INavigationAware) only seem to get called when navigating using Prism's NavigationService.
When using the hardware backbutton or the backbutton in the appbar the OnNavigatedTo and OnNavigatedFrom methods do not get called.
Is this a bug or am I missing something? When you can not rely on it, what is the use of INavigationAware?

This is a limitation of the current Xamarin.Forms platform: https://github.com/PrismLibrary/Prism/issues/744

Related

How can I use Navigator in onBackgroundMessageHandler of Firebase in killed state in Flutter?

I have developed a flutter app where it has calling feature with Agora SDK. In the latest version of firebase_messaging package, the method onBackgroundMessageHandler is made a separate isolate which will have its own context and memory.
Isolates should be
Top level methods or
Static methods inside the class.
when onBackgroundMessageHandler is made top-level function, the method doesn't get called in killed state in release mode. The solution for release mode issue is being solved as per most of the solutions provided by the flutter community.
The solution is to use #pragma like below
#pragma('vm:entry-point')
Future<void> onBackgroundMessageHandler(RemoteMessage message){}
This #pragma('vm:entry-point') is used to indicate the compiler that this method will be used from native code.
Using #pragma('vm:entry-point') poses an issue of not able to access the navigator context to show the incoming call.
Libraries used to achieve calling feature
Agora SDK for voice calling : agora_rtc_engine
Flutter Incoming Call for calling notification : flutter_incoming_call
GetX for navigation: get
Problems
Adding #pragma('vm:entry-point') does not provide Navigator in killed state to push a new screen.
Not Adding #pragma('vm:entry-point') does not work in the killed state.
I'm using flutter_incoming_call for showing the calling notification where I'm showing "Accept" and "Decline" buttons. Tapping on "Accept" button somehow I'm able to navigate to Incoming call screen but the next time when I'm trying to navigate to any screen without relaunching the app, throws an error as below
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].
I tried replacing this with global key implementation.
GlobalKey<NavigationState> navigatorKey = GlobalKey<NavigationState>();
This gives navigorKey.currentState as null.
I would need the help from Flutter community to resolve this issue of navigating to any screen from killed state in onBackgroundMessageHandler method of firebase.
If there are any other solutions, I'd like to hear them too. Please provide any suggestions.

Equivalent of Navigator.pushNamed with Navigator 2.0 in Flutter?

First: forgive me if it's a dumb question, but I'm trying to figure out step by step how Navigator 2.0 works and how to implement it in my app; this seems to be the only piece left of this puzzle but I weren't able to find an answer anywhere.
I've followed this Medium article on how to implement the new Navigator inside my Flutter app but I don't get how to use it after I've finished.
I mean: I have replaced MaterialApp with MaterialApp.router, specifying the custom RouterDelegate and the custom RouteInformationParser I've created, but how can I switch from the '/home' route to the '/profile' one after I pressed a button?
With the old navigator I would have added a Navigator.of(context).pushNamed('/profile) in the onPressed function of the button in the home screen, is it still valid or now should I proceed different?
For navigator 1.0:
Navigator.of(context).pushNamed('/profile');
For navigator 2.0 (using go_router package):
GoRouter.of(context).pushNamed('/profile');

Where should my automatic screen change occur - presentation or model?

I am using scopedModel approach in flutter, but the question still remains with other patterns like flutter.
-My UI calls authModel.login()
-authModel.login does async work and calls notifyListeners
-build is automatically triggered on my UI
-inside build method, UI checks the login state on authModel, then calls
addPostFrameCallback to change the screen from the build method.
Is this the best design? I feel like this is code smell, but I am not sure. Would it be better if the authModel was passed an onLoginCompleteCallback function from the UI that would change the screen, and then I would not need to call addPostFrameCallback in the build method?
The presentation on the screen is not dependant on the isLoggedIn bool at all. Its just observed to change the screen.

How should I tell flutter that my app needs rebuilding externally?

I want my app to get an intent, and depending on the intent to display something in the app.
Normally, when a widget depends on state, you put it in a State and run setState().
The issue is that when I try starting my flutter app with different intents, I just get I/FlutterActivityDelegate( 4472): onResume setting current activity to this. And in a way it makes sense - I'm not saying anywhere in the flutter code that my widget needs repainting - since I get my intent through Java.
On the other hand, there should be a way to tell flutter to repaint my widget by intent? Or is there something else I should do?
Specifically to get notified about onResume event you can use WidgetsBindingObserver. Implement its didChangeAppLifecycleState method and respond to AppLifecycleState.resumed by doing whatever it is you want the UI to do, such as call setState to trigger rebuild. That said, there needs to be an effective change for the UI to be repainted. Simply calling setState with no effective state change may not result (in fact, should not) in actual UI changes.
In general, you can send a message from Java (or Objective-C/Swift) to Flutter using BasicMessageChannel and make your app react to the message (e.g. call setState or schedule frames).

MvvmCross: How to navigate from regular view to Mvvm viewmodel on Android?

I am slowly migrating my app over to MvvmCross on Android. I have not converted all Activities over to ViewModels yet. Therefore, I need to navigate from an Mvvm-controlled Activity to a regular Activity. To do this, I made my own Presenter and intercepted the Show method and did my own StartActivity. That seemed to work. However, now I need to go the other direction and have my regular Activity go back to the original Mvvm-controlled Activity. I tried just doing a StartActivity on the ViewModel using CLEAR_TOP flag, but I got an error:
"Null Extras seen on Intent when creating ViewModel - this should not happen - have you tried to navigate to an MvvmCross View directly?"
How can I go back to the original Mvvm-controlled activity from a regular Activity?
Simple...
To go back from any standard Android Activity, you can simply ask the Activity to close using Finish()
But beyond that...
If instead you want to go forwards to an MvvmCross View, then you need to know a little about MvvmCross internals: in particular about how MvvmCross navigation conceptually happens between ViewModels rather than between Activities, Pages or UIViewControllers.
If you want to go forwards to a new ViewModel, then you can do this using the IMvxViewDispatcher singleton - how to do this is shown in Show view from non-view/viewmodel in mvvmcross
If you then later want to go back from the current ViewModel, then you can try calling Close(this) within the ViewModel - by default, on Android this will map to Finish(), on Touch to PopViewController, on WpDev to GoBack()
This seemed to work, but is a hack since I use a special string "MvxLaunchData".
Intent i = new Intent(this,typeof(LoginView));
i.AddFlags(ActivityFlags.ClearTop);
var converter = Mvx.Resolve<IMvxNavigationSerializer> ();
MvxViewModelRequest request = MvxViewModelRequest.GetDefaultRequest (typeof(LoginViewModel));
i.PutExtra ("MvxLaunchData", converter.Serializer.SerializeObject(request));
StartActivity(i);
I will try the method shown in the other question you referenced.