I would like to use permission for android 6 in my app but i saw a strange event. Perhaps you can help me about that.
If you start your app with "Dangerous" permissions, these permissions appears in the "App permissions" of your android device. PERFECT!
BUT if you keep your app in background, go to the "App permissions" menu, disable (you can enable and then disable it) a permission and go back to your app, android never go to onStart (Fragment or activity) ?! And never go there again.
If you don't touch to the permission or if you enable a permission => it go to onStart and others.
That's problematic, for exemple, if your app use listeners, you can't restart it and you can have a crash...
Do you know the method where Android go when you disable a permission ?
I tried
onCreate
onStart
onResume
onRestart
onRestoreInstanceState
onActionModeStarted
onRestoreInstanceState
onPostResume
onContentChanged
... but no way... :/
Here is my solution:
I use some fragments in my mainActivity.
As you know, the activity is recreated when user disable a permission => go through onCreate, ...
What i do in the onCreate(...) of my mainActivity, i remove all loaded fragments and put my app in the same state as a first run.
Like this:
// Clean fragments (only if the app is recreated (When user disable permission))
FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
// Remove previous fragments (case of the app was restarted after changed permission on android 6 and higher)
List<Fragment> fragmentList = fragmentManager.getFragments();
if (fragmentList != null) {
for (Fragment fragment : fragmentList) {
if (fragment != null) {
fragmentManager.beginTransaction().remove(fragment).commit();
}
}
}
Be careful !!! : I had a crash with the version 23.2.0 of appcompat and design libraries. This crash appear when the app is recreated !
Check this link for more info.
As already pointed out correct android is relaunching your app. This is the same behavior as when your app is in background and the system kills your application as more memory is used.
What happens when you go back to your application is that the last activity inclusiv fragment(s) is recreated.
Usually a start up screen (splash screen) is used to initialize the application.
Once the application is initialize (for example the services, viewmodel are ready) the startup-activity is switched to the main activity.
A common crash occurs in many applications when the app is recreated(for example revoke permissions) as the app is not initialized and the services or viewmodels are used which are null.
I don't think there is a way to avoid a recreation of the last activity after a app restart.
What you could do is to check if the application is initialized and otherwise switch to the startup activity and initialize the app.
Be aware that you have to handle unitialized applications in the activity and also the fragments.
Xamarin example code:
if (!((MyApplication)ApplicationContext).IsInitialized)
{
Intent intent = new Intent(Application.Context,typeof(StartupActivity));
intent.SetFlags(ActivityFlags.NewTask);
StartActivity(intent);
Finish();
}
As soon as base.onCreate is called the fragments are created so even the provided "workaround" from acs-team does not avoid the recreation of the last fragment.
With the above provided sample code the lifecycle will be in case the activity had a fragment:
- Revoke permission app gets killed
- Restart app
- Application OnCreate
- LastActivity.OnCreate
- LastFragment.OnAttach
- LastFragment.OnCreate
- LastFragment.OnCreateView
- LastFragment.OnViewCreated
- LastFragment.OnDestroy
- LastFragment.OnDettach
- LastActivity.OnDestroy
- StartupActivity.OnCreate
By the way you can also test an app restart over the adb shell:
Open your app then go to the android home screen in order that your app is in the background
adb shell "ps | grep <com.yourpackage>" // get the app process id
adb shell run-as <com.yourpackage> kill <app-process-id> // kill the app
start the your app again over the icon or the recent tasks