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

Whats the correct way for lazy Router? #559

Open ursusursus opened 5 years ago

ursusursus commented 5 years ago

Hi, I have a layer in the UI that is only used rarely (pin code feature). I implemented it via new controller container above the "default" controller container.

Now I'd like to lazily initialize the Router, however it takes the savedInstanceState, and I presume its designed to be called in onCreate, not lazily anywhere for example in onResume

Has anyone encountered this? Is it worth avoiding at all? I'd also like to use ViewStub for best optimization however, its pointless if Router needs to be created in onCreate where savedState is accessible

manueldidonna commented 5 years ago

I would use the same router of the root/default container. The pin code screen could be shown as a controller with a changehandler that doesn't remove the 'from' view

ursusursus commented 5 years ago

Not a great solution, as you need extra code to prevent somebody accidentally pushing a controller on top of pin. New router is safe I think

dimsuz commented 5 years ago

You can pass null as saved state. Our is this not an option for you as it will skip restoring a backstack?

manueldidonna commented 5 years ago

I generally use an extension function for Router to push controllers with standard rules/transitions

Maybe you can do something similar

// Implemented by every controller related to pin code feature 
interface PinCodeRoute

//  the controller must implement PinCodeRoute if the latest pushed controller did
fun Router.pushWithStandardRules(controller): Boolean
ursusursus commented 5 years ago

You can pass null as saved state. Our is this not an option for you as it will skip restoring a backstack?

Yea exactly, if use is using the pincode and it was displayed, it wont get restored

dimsuz commented 5 years ago

We have some apps which use pin code, and we still are passing null to avoid restoring backstack, because we configure it ourselves. Basically, for pin code we store a flag between launches which is then used on app start to determine which controller should be the first one — pin code or some other one.

ursusursus commented 5 years ago

@dimsuz right, but you still need to call Conductor.attachRouter in onCreate after rotation happened, otherwise controller will disappear from the router after rotation. Btw do you use single router or have a separate router for pincode controller?

ursusursus commented 5 years ago

Here is what I ended up with, using a static member, its ugly but works

private var wasPinCodeRouterInitialized = false

class Activity {

    private var pinCodeRouter: Router? = null

    onCreate(savedState) {
        if (wasPinCodeRouterInitialized) {
            pinCodeRouter = createPinCodeRouter(savedState)
        }
    }

    onResume() {
        if (someBusinessLogicOfShouldDisplayPinCode()) {
            if (pinCodeRouter == null) {
                pinCodeRouter = createPinCodeRouter(savedState)
                wasPinCodeRouterInitialized = true
            }
            pinCodeRouter.pushController(transaction(PinCodeController()))
        }
    }

}
dimsuz commented 5 years ago

@ursusursus we don't handle rotation, lock orientation to portrait (runs away and hides in bushes). We use a single router for the whole app.