bluelinelabs / Conductor

A small, yet full-featured framework that allows building View-based Android applications
Apache License 2.0
3.9k stars 343 forks source link

Broken on Android 12 #661

Closed ursusursus closed 2 years ago

ursusursus commented 2 years ago

Hi, when running on Android 12 (Pixel 5), after backpress activity is only paused/stopped, not destroyed. After resuming/starting, library is in a weird invalid state, parentController is null when is shouldn't be etc, causing crashes.

This doesn't happen, if the activity is paused/stopped via home button, and then resumed.

Possibly related to https://github.com/bluelinelabs/Conductor/issues/659

@PaulWoitaschek @EricKuck

ursusursus commented 2 years ago

Any pointer where should I look to attempt a pr?

DavidBertet commented 2 years ago

I was facing the same issue, unfortunately I'm not sure how it can be fixed in Conductor itself. The router is used recursively, and popping the last controller is required in most cases.

Let's explain

My activity was calling router.handleBack() in onBackPressed as in the example

The issue is, when the user taps the back button on the root controller with Android 12

=> When the user comes back, the controller has already been destroyed, nothing is going to recreate it. That doesn't happen with the home button as onBackPressed isn't called, so the controller doesn't pop.

To avoid popping the root controller, we can update the code of the activity as is

override fun onBackPressed() {
    if (router.backstackSize <= 1 || !router.handleBack()) {
        super.onBackPressed()
    }
}

PS: My case is slightly more different as I used a childRouters for each tabs. I check for the backstackSize of the childRouter currently visible, but the idea is basically the same - never pop the head as it won't come back!

EricKuck commented 2 years ago

Version 3.1.3 of the app has a fix for this. Unfortunately this type of issue is impossible to fix automatically in the library, but it exposes a new Router.setPopRootControllerMode method that allows you to control what happens when it comes time to pop the final controller of a router. Options are:

ursusursus commented 2 years ago

Could you please show to use this, to solve this issue? If os >= Android12 then NEVER else POP_ROOT_CONTROLLER_BUT_NOT_VIEW ?

EricKuck commented 2 years ago

What's the harm in always using NEVER?

ursusursus commented 2 years ago

I'm not sure, I'm just trying to replicate Android 11 behavior on the 12.

So, if it is NEVER then on 12 it doesnt pop it, so that fixes the issue, and below 12 it doesn't matter, since the activity is getting destroyed anyways, right?

EricKuck commented 2 years ago

Yes that's correct. I will personally be using NEVER in Activities regardless of OS version. If you do decide you want to prevent this change from affecting Android 11 and below for whatever reason you could always use something like router.setPopRootControllerMode(if (Build.VERSION.SDK_INT >= 31) PopRootControllerMode.NEVER else PopRootControllerMode.POP_ROOT_CONTROLLER_BUT_NOT_VIEW)

ursusursus commented 2 years ago

Right, I wonder if this should be the default behavior of Router

EricKuck commented 2 years ago

It may be in the future, but this would break some of today's use cases. If it becomes the default behavior, it would happen in a major version bump.