Issue
I want to create an Android app which has a specific Activity that acts as a 'Root Launcher Activity', to sometimes launch other Activities in the app. When this Root Launcher Activity starts, it will check a preference to see if it can directly launch a different Activity.
For many years on Android 11 (API 30) and below, this worked fine:
LoginActivity.kt
/** This is the main entry point of the app, when the user clicks the app icon. */
class LoginActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// If the user is already logged in, don't show the Login screen.
// Instead proceed directly to the Welcome screen.
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
val userIsLoggedIn = prefs.getBoolean("USER_IS_LOGGED_IN", false)
if (userIsLoggedIn) {
launchWelcomeScreenActivity()
finish() // Close LoginActivity
} else {
displayLoginFields()
}
}
override fun onResume() {
super.onResume()
Log.d("MyApp", "onResume()")
// Nothing to do here
}
...
}
AndroidManifest.xml
...
<application
android:icon="@drawable/app_icon">
<activity
android:name=".LoginActivity"
android:exported="true">
<!-- This Activity is the main entry point to the app. Create an app icon for it. -->
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
...
</application>
...
Now suppose that the user clicks a "Log Out" button on the WelcomeScreenActivity
. It should log the user out, but remain on that screen with an image displayed:
class WelcomeScreenActivity : AppCompatActivity() {
fun onLogoutClicked() {
// Clear the logged in state and display an image
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
prefs.edit().putBoolean("USER_IS_LOGGED_IN", false).apply()
showLoggedOutImage()
}
}
When the user presses the Back button, they will exit out of the app, because WelcomeScreenActivity
is the only one left on the stack.
But now the problem is on Android 12 and above: When the user relaunches the app by clicking on the app icon, it will launch LoginActivity.onResume()
and show the wrong screen. It's because LoginActivity.onCreate()
is no longer called in this situation, due to the Activity lifecycle behavior changes, for Android 12/13 , quoted below:
Root launcher activities are no longer finished on Back press.
Android 12 changes the default handling of the system Back press on launcher activities that are at the root of their tasks. In previous versions, the system would finish these activities on Back press. In Android 12, the system now moves the activity and its task to the background instead of finishing the activity. The new behavior matches the current behavior when navigating out of an app using the Home button or gesture.
What I wanted and expected is that it should launch LoginActivity.onCreate()
and call displayLoginFields()
, just like on Android 11 and below. There is no obvious way to make the LoginActivity
restart from a fresh state after the Back button exit, on Android 12.
So what is the correct way to handle this logic for a root launcher to work on all Android OS versions?
- Should I move the launcher code from
onCreate()
intoonResume()
oronNewIntent()
? Will this have any side-effects? - Should I check if the app is running on Android 12 in
onResume()
, and use specific behavior for it, something like this:
/** This is the main entry point of the app, when the user clicks the app icon. */
class LoginActivity : AppCompatActivity() {
...
override fun onResume() {
super.onResume()
val ANDROID_12_API_31 = 31
if (Build.VERSION.SDK_INT >= ANDROID_12_API_31) {
// Add the Activity launcher code from onCreate()
}
}
...
}
- Is there a way on Android 12 to force
LoginActivity.onCreate()
to be called after a relaunch from the Back button press?
Similar/related question, but not quite the same problem: How to set the root of the navigation stack
Note that Android 12 was released in October 2021.
Solution
Why not just override onBackPressed()
so that it finishes the Activity
rather than calling super.onBackPressed()
? Then the old Back button behavior will be restored.
Answered By - Gavin Wright
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.