Android Back Button Problems

THis is starting to drive me a little nuts. I’m trying to implement some simple actions for the Android back button, and running into some problems.

First, i’ve already looked at the blog post here: http://www.coronalabs.com/blog/2013/03/26/androidizing-your-mobile-app/

And have searched up and down the forums for answers. My code is very simple:

local function onKeyEvent( event )    local phase = event.phase    local keyName = event.keyName    print( event.phase, event.keyName )        if ( "back" == keyName and phase == "up" ) then        storyboard.gotoScene( "menu", { effect="slideRight", time=800})     end    return true end function scene:exitScene( event )    local group = self.view        Runtime:removeEventListener( "key", onKeyEvent )      end  

The problem i’m having is that halfway through the transition back to “menu” it crashes/closes.

After doing some playing around, i’ve figured out that the Back button is firing off twice? I figured this out by putting the same function in the “menu” scene but telling it to do nothing if the back button is pushed. By doing this, it then works like I want. But that doesn’t solve the problem, as I also need to put this code on a overlay, and the same thing is happening (The overlay closes, but the back button fires a second time transitioning back to the menu).

I’ve tried adding a event.phase == “ended” wrapper

I’ve tried adding 2 if statements, one for the “up” phase that does the transition and one for the “down” phase which does nothing.

Nothing seems to work, and the blog doesn’t help.

Forgot to mention I’m adding the Runtime listener for the key to every createScene function, and as you can see above removing it on exit.

Hi @spowell83,

My first guess is that you’re getting duplicate Runtime listeners on the key event, however and whenever you’re creating them. Are you creating another listener in the overlay, such that you already have one running, then you create another when the overlay loads?

Brent

Hi Brent, OH! I am creating another listener for the overlay. I’m going to try some things out and see what happens.

Why not add the event listener in main.lua and put the function there and only call it once?

I ended up fixing the problem. It had to do with the same reason why I didn’t do what Rob suggested. I wasn’t understanding the scope between the overlay and scene under it properly.

I’m both rusty with programming (Been a few years) and very new to LUA and non-OO environment. So I’m still learning the scope/structure of LUA/Storyboard.

This probably is a stupid question. But if I declare a Runtime Listener in the Main.lua along with the handling function, will it still call that function even if I’m currently on a different scene (lua file)? How would I go about doing what Rob suggested?

main.lua is always in memory, but like any other lua module, local functions are scoped to it only, global functions are available everywhere.  But you don’t need globals in this case.  If you declare your event listener in main.lua to use a local function to main.lua, it will get the address (because it exists and is in scope) and register it.  Regardless of other scenes, that function is still around too.

Scenes are modules too and their code hangs around as long as that module doesn’t get un-required, which is what storyboard.removeScene() does.  So if you have a runtime listener trying to run code in a module that gets removed, things go crash on you.

But putting a runtime in main.lua to run a function in main.lua is safe.  Of course that function’s code has to handle running regardless of what scene you are in… meaning nothing in your scene is in scope for that function unless you’re doing something like the mydata module we talked about in the No More Globals blog or you’ve attached the data to the storyboard object or some similar technique.

Ohhhhh, that totally helps! And I can use the Storyboard object to hold flags (Whether or not the current scene is a overlay for instance) and that should be readable by the function in main.lua.

Thanks Rob!

You guys that help us poor shmucks that are still learning are amazing!

It might be worth reading this blog post:

http://www.coronalabs.com/blog/2013/05/28/tutorial-goodbye-globals/

If you haven’t already.  I’ve used the adding stuff to the storyboard object trick for a long time, but to be 100% future proof, you probably should use the “mydata” technique in that blog post rather than using storyboard.  You might use a variable name that we might use in the future and suddenly your app stops working.  It’s pretty low risk, especially if you name space your variables.  Yea, you have to type in an extra line in each storyboard module, but, it is the safest way to deal with inter-scene data.

Hi @spowell83,

My first guess is that you’re getting duplicate Runtime listeners on the key event, however and whenever you’re creating them. Are you creating another listener in the overlay, such that you already have one running, then you create another when the overlay loads?

Brent

Hi Brent, OH! I am creating another listener for the overlay. I’m going to try some things out and see what happens.

Why not add the event listener in main.lua and put the function there and only call it once?

I ended up fixing the problem. It had to do with the same reason why I didn’t do what Rob suggested. I wasn’t understanding the scope between the overlay and scene under it properly.

I’m both rusty with programming (Been a few years) and very new to LUA and non-OO environment. So I’m still learning the scope/structure of LUA/Storyboard.

This probably is a stupid question. But if I declare a Runtime Listener in the Main.lua along with the handling function, will it still call that function even if I’m currently on a different scene (lua file)? How would I go about doing what Rob suggested?

main.lua is always in memory, but like any other lua module, local functions are scoped to it only, global functions are available everywhere.  But you don’t need globals in this case.  If you declare your event listener in main.lua to use a local function to main.lua, it will get the address (because it exists and is in scope) and register it.  Regardless of other scenes, that function is still around too.

Scenes are modules too and their code hangs around as long as that module doesn’t get un-required, which is what storyboard.removeScene() does.  So if you have a runtime listener trying to run code in a module that gets removed, things go crash on you.

But putting a runtime in main.lua to run a function in main.lua is safe.  Of course that function’s code has to handle running regardless of what scene you are in… meaning nothing in your scene is in scope for that function unless you’re doing something like the mydata module we talked about in the No More Globals blog or you’ve attached the data to the storyboard object or some similar technique.

Ohhhhh, that totally helps! And I can use the Storyboard object to hold flags (Whether or not the current scene is a overlay for instance) and that should be readable by the function in main.lua.

Thanks Rob!

You guys that help us poor shmucks that are still learning are amazing!

It might be worth reading this blog post:

http://www.coronalabs.com/blog/2013/05/28/tutorial-goodbye-globals/

If you haven’t already.  I’ve used the adding stuff to the storyboard object trick for a long time, but to be 100% future proof, you probably should use the “mydata” technique in that blog post rather than using storyboard.  You might use a variable name that we might use in the future and suddenly your app stops working.  It’s pretty low risk, especially if you name space your variables.  Yea, you have to type in an extra line in each storyboard module, but, it is the safest way to deal with inter-scene data.