Open NightOwlCoder opened 8 years ago
I get the same situation when running UWP on a WP emulator.
Droid is the only one that is actually working fine.
I've also asked this question on SO: http://stackoverflow.com/questions/35142319/xamarin-forms-start-sleep-resume-not-being-called-when-using-mvvmcross-forms
https://github.com/MvvmCross/MvvmCross-Forms/blob/master/MvvmCross.Forms.Presenter.Core/MvxFormsApp.cs#L14 do they get called in a normal Forms app?
Brand new solution on VS does the expected:
using Xamarin.Forms;
using System.Diagnostics;
namespace XS.Forms
{
public class App : Application
{
public App()
{
MainPage = new ContentPage
{
Content = new StackLayout
{
VerticalOptions = LayoutOptions.Center,
Children = { new Label { XAlign = TextAlignment.Center, Text = "Welcome to Xamarin Forms!" } }
}
};
}
protected override void OnStart()
{
Debug.WriteLine("start");
}
protected override void OnSleep()
{
Debug.WriteLine("sleep");
}
protected override void OnResume()
{
Debug.WriteLine("resume");
}
}
}
Console output for iOS run:
Launching 'XSFormsiOS' on 'iPhone 6s Plus iOS 9.2'...
Thread started: #2
Thread started: #3
2016-02-02 09:45:17.895 XSFormsiOS[82830:5257324] start
2016-02-02 09:45:32.227 XSFormsiOS[82830:5257324] sleep[0:] sleep
2016-02-02 09:45:37.095 XSFormsiOS[82830:5257324] resume[0:] resume
2016-02-02 09:45:39.410 XSFormsiOS[82830:5257324] sleep[0:] sleep
2016-02-02 09:45:40.799 XSFormsiOS[82830:5257324] resume
The app has been terminated.
and Console output for Droid run:
Android application is debugging.
InspectorDebugSession(0): HandleTargetEvent: TargetReady
Thread started: #3
02-02 09:39:51.988 I/mono-stdout( 2015): start
02-02 09:39:52.183 I/mono-stdout( 2015): sleep
02-02 09:40:16.844 I/mono-stdout( 2015): resume
02-02 09:40:24.163 I/mono-stdout( 2015): sleep
02-02 09:40:35.610 I/mono-stdout( 2015): resume
InspectorDebugSession(0): HandleTargetEvent: ThreadStopped
Thread started: <Thread Pool> #7
InspectorDebugSession(0): HandleTargetEvent: ThreadStarted
InspectorDebugSession(0): Disposed
I switched the app a few times to BG and back.
Are you sure that your mvxFormsApp
isn't GC'ed? Try creating it as a member variable.
As it goes as a parameter to the presenter and it saves it, I did not think it was necessary.
new MvxFormsIosPagePresenter(Window, mvxFormsApp);
Anyway, I created a local fiend but unfortunately, got the same end result.
So I got the source code for the presenter, and added the Example002XAML PCL/iOS into it, removed packages from it and pointed to src code on the solution.
Created a default ctor on MvxFormsApp
and put a BP there and on the 3 overrides.
Unfortunately, only the ctor one is hit, the overrides never came.
But as I already tested a pure Form app and they are calling this, looks like we are doing something out of order?
Any other idea that can help me move further in the investigation?
Something else I just found, there is no LoadApplication
in iOS code.
Isn't it necessary like on the other platforms?
Probably exactly what is missing?
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
Above code is from a pure Xamarin Forms iOS project.
But unfortunately LoadApplication
is only available if we inherit from Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
.
Looks like we need some refator on the base class here?
Is there any update on this one? Is there a workaround?
This probably also causes the Start/ReloadState/SaveState to be not called on iOS.
I solved this in my current project by doing the following:
public class MyApplicationDelegate : FormsApplicationDelegate, IMvxApplicationDelegate
{
public override void WillEnterForeground(UIApplication application)
{
FireLifetimeChanged(MvxLifetimeEvent.ActivatedFromMemory);
}
public override void DidEnterBackground(UIApplication application)
{
FireLifetimeChanged(MvxLifetimeEvent.Deactivated);
}
public override void WillTerminate(UIApplication application)
{
FireLifetimeChanged(MvxLifetimeEvent.Closing);
}
public override void FinishedLaunching(UIApplication application)
{
FireLifetimeChanged(MvxLifetimeEvent.Launching);
}
private void FireLifetimeChanged(MvxLifetimeEvent which)
{
var handler = LifetimeChanged;
if (handler != null)
handler(this, new MvxLifetimeEventArgs(which));
}
#region IMvxLifetime implementation
public event EventHandler<MvxLifetimeEventArgs> LifetimeChanged;
#endregion
}
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
Forms.Init();
Forms.ViewInitialized += (sender, e) =>
{
if (!string.IsNullOrWhiteSpace(e.View.StyleId))
{
e.NativeView.AccessibilityIdentifier = e.View.StyleId;
}
};
var formsApp = new MyFormsApp();
var setup = new Setup(this, formsApp);
setup.Initialize();
var startup = Mvx.Resolve<IMvxAppStart>();
startup.Start();
LoadApplication(formsApp);
return base.FinishedLaunching(app, options);
}
Basicly the solution consists in using LoadApplication and removing the explicit window.
Thanks! How does your Setup and FormsApp class look like? Do I need to initialize the MainPage in the FormsApp class? What did you pass to the MvxIosSetup base class constructor?
My setup looks like this:
public class Setup : MvxIosSetup
{
private readonly Xamarin.Forms.Application _app;
public Setup(IMvxApplicationDelegate applicationDelegate, Xamarin.Forms.Application app)
: base(applicationDelegate, window: null)
{
_app = app;
}
protected override IMvxApplication CreateApp()
{
return new MyMvxApp();
}
protected override IMvxTrace CreateDebugTrace()
{
return new DebugTrace();
}
protected override IMvxIosViewPresenter CreatePresenter()
{
var presenter = new MyIosFormsViewPresenter(_app);
return presenter;
}
}
MyFormsApp (inside the PCL) is just:
public class MyFormsApp : MvxFormsApp
{
protected override void OnStart()
{
// Handle when your app starts
Mvx.Trace("App start");
}
protected override void OnSleep()
{
// Handle when your app sleeps
Mvx.Trace("App sleep");
}
protected override void OnResume()
{
// Handle when your app resumes
Mvx.Trace("App resume");
}
}
My custom presenter is something like (the window reference is not needed):
public class MyIosFormsViewPresenter : MvxFormsPagePresenter, IMvxIosViewPresenter
{
public MyIosFormsViewPresenter(Xamarin.Forms.Application mvxFormsApp)
: base(mvxFormsApp)
{
}
public bool PresentModalViewController(UIViewController controller, bool animated)
{
return false;
}
public void NativeModalViewControllerDisappearedOnItsOwn()
{
}
}
Thanks!
Do the application lifecycle events work correctly for you?
On android, the OnResume method on the FormsApplication does not get called, when bringing the app to foreground, but the OnStart method is called instead.
On iOS the OnResume method on the FormsApplication works, but the OnStart method is not invoked on the ViewModel on resume.
The SaveStateToBundle and ReloadFromBundle methods on my view model are never executed, neither on android nor iOS.
These application lifecyle methos have nothing to do with the view models direclty (or at least out of the box). They work fine for my app.
The Start method of the MvxViewModel is called after the view model is instantiated by the ViewPresenter.
I had to forward these events to my view model manually. For example, for 'App -> OnResume' I get the topmost view (Page), then I get the binding context and if the binding context is my BaseViewModel then I call OnResume on it.
I can't tell you more about SaveStateToBundle and ReloadFromBundle because I'm not using them in my forms app but I guess they also need to be triggered.
Moreover, I defined methods like OnSuspended, OnResumed, OnLoaded etc in my BaseViewModel and trigger them from a BasePage by overriding Page methods like OnAppearing, OnDissapearing, OnBindingContextChanged, OnBackButtonPressed. This way my ViewModels are aware of the state of their views.
Hey there,
I've code like this on MvxIosSetup:
But those methods are never called.
Is this a known issue or am I doing something wrong?