How to get notified when Xamarin Native Android app goes to sleep or is terminated? - xamarin.android

How to get notified when Xamarin Native Android app goes to sleep or is terminated?
When searching, I only found an answer for Xamarin.Forms where the Application object allows to override OnSleep.
The background of this question is that I want to save settings when the app either goes to background or is terminated.

Just like the OnSleep method of Xamarin Forms the OnPause method is called in Android Native when the app goes into the background.
You can override OnPause in both an Activity and a Fragment something like this:
protected override void OnPause()
{
base.OnPause();
// Add your code here
}
Update
You can do the same on application level by adding the Android Application class :
Add a new C# class file in your project called MainApplication.cs.
Then add the Application.IActivityLifecycleCallbacks interface where you can find the activity paused method with the activity context in which it was paused so you can add it and do the needful.
#if DEBUG
[Application(Debuggable = true)]
#else
[Application(Debuggable = false)]
#endif
public class MainApplication : Application , Application.IActivityLifecycleCallbacks
{
public MainApplication(IntPtr handle, JniHandleOwnership transer)
: base(handle, transer)
{
}
public void OnActivityPaused(Android.App.Activity activity)
{
base.OnCreate();
// Add some code
}
public override void OnTerminate()
{
base.OnTerminate();
UnregisterActivityLifecycleCallbacks(this);
}
public override void OnCreate()
{
base.OnCreate();
RegisterActivityLifecycleCallbacks(this);
}
}

Related

How can I Get Xamarin iOS Application to Automatically Sense Light and Dark Changes?

Someone here (thanks sushihangover!) helped me get my application to read the iOS Settings Dark or Light theme on command. I'm using Xamarin (not Forms). I also need the following (just for iOS):
iOS Settings Theme is Light
App is set to Automatic, so it uses current the iOS Settings Theme (Light)
App launched is Light
Home button press
Change iOS Settings to Dark
Bring app to foreground
App still look Light, but it should look Dark.
I realize the AppDelegate has a WillEnterForeground method, but I don't know how to wire that up so the App looks Dark when it comes to the foreground. I'm using MvvmCross. The following link looks promising.
https://forums.xamarin.com/discussion/181648/best-approach-to-handle-dark-theme
I don't understand how to apply the link's contents to my MvvmCross architecture.
Your help is appreciated!
Thanks!
Larry
The best way to react on application changes while using the MVVM pattern would be to implement a IThemeService interface as shown in your link.
xamarin forms iOS
But I think it's not possible to react to configuration changes in Xamarin.Forms.iOS plattform while using MvvmCross. I looked into the source code of the MvvmCross.Forms.iOS project and couldn't find any equivalent to the MvvmCross.Forms.Android setup methods like OnConfigurationChanged.
On Android you can easily refresh the app-theme while change the system theme in the MainActivity.
public class MainActivity : MvxFormsAppCompatActivity
{
public override void OnConfigurationChanged(Configuration newConfig)
{
base.OnConfigurationChanged(newConfig);
this.UpdateTheme(newConfig);
}
protected override void OnResume()
{
base.OnResume();
UpdateTheme(Resources.Configuration);
}
protected override void OnStart()
{
base.OnStart();
this.UpdateTheme(Resources.Configuration);
}
private void UpdateTheme(Configuration newConfig)
{
if (Build.VERSION.SdkInt >= BuildVersionCodes.Froyo)
{
var uiModeFlags = newConfig.UiMode & UiMode.NightMask;
switch (uiModeFlags)
{
case UiMode.NightYes:
Mvx.IoCProvider.Resolve<IThemeService>().UpdateTheme(BaseTheme.Dark);
break;
case UiMode.NightNo:
Mvx.IoCProvider.Resolve<IThemeService>().UpdateTheme(BaseTheme.Light);
break;
default:
throw new NotSupportedException($"UiMode {uiModeFlags} not supported");
}
}
}
}
But in the AppDelegate on the iOS plattform, you don't have any of these functionalitys to override.
public class AppDelegate : MvxFormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
return base.FinishedLaunching(application, launchOptions);
}
}
I copied this code from this project.
native xamarin iOS
When you are using native iOS you could override the TraitCollectionDidChange method. It's the equivalent to the android OnConfigurationChanged function.
Maybee look here for more details. I adapted the android version to iOS for you. At First, you have to create a custom view controller.
// your supported theme versions
public enum BaseTheme
{
Inherit = 0,
Light = 1,
Dark = 2
}
public class MyViewController : UIViewController
{
public override void TraitCollectionDidChange(UITraitCollection previousTraitCollection)
{
base.TraitCollectionDidChange(previousTraitCollection);
if (TraitCollection.UserInterfaceStyle != previousTraitCollection.UserInterfaceStyle)
{
UpdateTheme(TraitCollection.UserInterfaceStyle);
}
}
private void UpdateTheme(UIUserInterfaceStyle newConfig)
{
switch(newConfig)
{
case UIUserInterfaceStyle.Dark:
Mvx.IoCProvider.Resolve<IThemeService>().UpdateTheme(BaseTheme.Dark);
break;
case UIUserInterfaceStyle.Light:
Mvx.IoCProvider.Resolve<IThemeService>().UpdateTheme(BaseTheme.Light);
break;
default:
throw new NotSupportedException($"UiMode {uiModeFlags} not supported");
}
}
}
I uploaded a project where I simplify coded an implementation for native IOS and android here. Complete and improve some things and it will work. Also look at the StarWars and TipCalc Project in the mvvmcross sample repo.
mvvmcross ioc
your interface structure could look like so;
IThemeService (base project) - ThemeService (base project) - ThemeService(iOS project)
And you have to register the interface of course.
Mvx.IoCProvider.RegisterSingleton<IThemeService>(() => new ThemeService());

Splash Screen disappeared after Application.OnCreate was overridden

Initial Issue
I need to register ProcessLifecycleOwner as described here Xamarin.Android Architecture Components in my Application.OnCreate method.
But it had resulted in the error with 6.2.2 version of MvvmCross:
MvvmCross.Exceptions.MvxIoCResolveException: Failed to resolve type MvvmCross.ViewModels.IMvxAppStart occurred
or just stuck on the Splash Screen with 6.2.3.
Fix
Those problems were fixed by advice from Xamarin.Android mvvmcross app crashes when launching with intent filter.
[Application]
public class App : MvxAndroidApplication<Setup, Core.App>
{
public App(IntPtr reference, JniHandleOwnership transfer) :
base(reference, transfer) { }
public override void OnCreate()
{
MvxAndroidSetupSingleton
.EnsureSingletonAvailable(ApplicationContext)
.EnsureInitialized();
base.OnCreate();
}
}
Current Issue
However Splash Screen dissapeared too, only blue background from default theme was left.
A workaround I've found:
public override void OnCreate()
{
Task.Run(() => MvxAndroidSetupSingleton
.EnsureSingletonAvailable(ApplicationContext)
.EnsureInitialized());
base.OnCreate();
}
But due to parallelism it is not reliable, sometimes works, sometimes crashes.
Question
How Splash Screen can be restored?
Your approach is most likely blocking on the UI thread which us causing the UI to block during the time that the expected splash screen is suppose to show.
Try using an async event handler to allow for a non blocking UI call
[Application]
public class App : MvxAndroidApplication<Setup, Core.App> {
public App(IntPtr reference, JniHandleOwnership transfer) :
base(reference, transfer) {
EnsureInitialized = onEnsureInitialized; //Subscribe to event
}
private event EventHandler EnsureInitialized = delegate { };
private async void onEnsureInitialized(object sender, EventArgs args) {
await Task.Run(() => MvxAndroidSetupSingleton.EnsureSingletonAvailable(ApplicationContext)
.EnsureInitialized());
}
public override void OnCreate() {
EnsureInitialized(this, EventArgs.Empty); //Raise event
base.OnCreate();
}
}

How to exit the App in Xamarin Forms?

My project is built with master-detail navigation.
There are totally three pages in the list named as Resources, Contacts, and Login.
Everything works fine in iOS, but when the user presses the Droid/WinPhone devices hardware back button, the app should exit.
Is there any app-exit mechanism for Xamarin Forms which will work on all the devices.? (I mean native code not platform dependent)
Thanks in advance.
I did that on this way
In xamarin forms I added interface
public interface INativeHelper
{
void CloseApp();
}
In android project I made implementation of INativeHelper
public class NativeHelper : INativeHelper
{
public void CloseApp()
{
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
}
}
Implementation of INativeHelper in IOS
public class NativeHelper : INativeHelper
{
public void CloseApp()
{
Process.GetCurrentProcess().CloseMainWindow();
Process.GetCurrentProcess().Close();
}
}
And then just override method OnBackButtonPressed in page in Xamarin.Forms project
protected override bool OnBackButtonPressed()
{
INativeHelper nativeHelper = null;
nativeHelper = DependencyService.Get<INativeHelper>();
if (nativeHelper != null)
{
nativeHelper.CloseApp();
}
return base.OnBackButtonPressed();
}
I didn't made implementation for WinPhone, but it should be similar.
You can use a DepedencyService for closing an app when your physical back button is pressed:
In your UI (PCL), do the following:
protected override bool OnBackButtonPressed()
{
if (Device.OS == TargetPlatform.Android)
DependencyService.Get<IAndroidMethods>().CloseApp();
return base.OnBackButtonPressed();
}
Now implement the Android-specific logic in your Android project:
[assembly: Xamarin.Forms.Dependency(typeof(AndroidMethods))]
namespace Your.Namespace
{
public class AndroidMethods : IAndroidMethods
{
public void CloseApp()
{
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
}
}
}
Also create an Interface (in your UI PCL):
public interface IAndroidMethods
{
void CloseApp();
}
As far as I know there is no native way to exit the app in Xamarin application.
The only way is to use dependency service. Override OnBackButtonPressed function in your ContentPage and check it is the last page:
protected override bool OnBackButtonPressed()
{
if(navigation.NavigationStack.Count == 1)//navigation is MainPage.Navigation
DependencyService.Get<YourDependencyInterface>().CloseApp();
}
For Android in YourAndroidDependency class:
public void CloseApp()
{
(Xamarin.Forms.Forms.Context as Activity).Finish();
}
As for WinPhone I'm not sure but I believe it can be done in same way - dependency service.
Having experimented with all the above, I found that none of the above worked on a Google Pixel 3a, with latest version of Android
The command that came closest was
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
However it left the remains of the app still visible in the background.
The following worked for me when called from the Android Main Activity
public void ExitApp()
{
this.FinishAndRemoveTask();
Android.OS.Process.KillProcess(Android.OS.Process.MyPid());
}
The first line FinishAndRemoveTask removes the app from both the foreground and the background, however the Application process is still active, hence the need for the second command.
This is the more easy way found:
public void QuitApp(object sender, EventArgs args)
{
Process.GetCurrentProcess().CloseMainWindow();
Process.GetCurrentProcess().Close();
}
PS: Tested in android
You can use Environment.Exit(0);

Blackberry foreground after background

When my app is running in background and I click its icon, it comes from background to foreground. Which function is triggered at first? I searched, after coming from background it triggers the public void activate() in the class which is extended by Application.
Now I have a GUI class, lets say Login.java, which extends UiApplication. What should I write in this class to see that Application has come from background to foreground?
And when going to Background I use this code
public boolean onClose() {
UiApplication.getUiApplication().invokeAndWait(new Runnable() {
public void run() {
MyScreen.setBackgroundFlag("true");
UiApplication.getUiApplication().requestBackground();
};
});
//Application.getApplication().requestForeground();
//System.exit(0);
return true;
}

Know when the device is completely turned on

I am developing an application where I want to integrate the SQL database in it. As far my code works fine. I made the application auto-run on startup and I check immediately for SDCard presence. If present I will create the database on SDCard and if not I will create it on device.
The problem is that when the application is auto-run, it will start before the device locates the SDCard, so I am always unable to detect if the SDCard is present.
What listener should I use to know that the device is completely turned on?
SystemListener will do the job. This is how I usually do it:
public class MyApp extends Application implements SystemListener {
public static void main(String[] args){
MyApp app = new MyApp();
if (ApplicationManager.getApplicationManager().inStartup()) {
app.addSystemListener(app);
//wait for powerUp callback
} else {
app.startup();
}
}
public void powerUp() {
removeSystemListener(this);
startup();
}
private void startup(){
//Perform initialization here, most typically show first screen and stuff.
}
// Remaining SystemListener callbacks not shown for brevity
}

Resources