Storyboard GoToScene Doesn't Work Properly With "Back" Button On Android

so i’m trying to figure out how to implement a “function” into physical back button on Android. then I found an explanation about “OnKeyEvent”. I tried to implement the standard GoToScene feature in storyboard for the “back” button, this is my code:

local function onKeyEvent( event ) -- Print which key was pressed down/up to the log. local message = "Key '" .. event.keyName .. "' was pressed " .. event.phase print( message ) if (event.keyName == "back" and event.phase == "up") then storyboard.gotoScene("scene3", {time=250, effect="crossFade", params = options}) print (" ok success") return true end return false end -- Add the key event listener. Runtime:addEventListener( "key", onKeyEvent );

when I test this in my android phone, it doesnt work properly. I mean, if I hit “back” button in that scene, yeah it changed scene but then it instantly changed scene again from the next one (where I also implement the onKeyEvent codes there). Basically it works like this within just one single touch on the “back” button: scene1 -> scene3 -> blank screen

when I check the log in eclipse logcat, apparently the key was like “pressed” twice because I saw the same print message twice as if I hit the back key several times. May I know what I did wrong?

I have always noticed in Lua that if you assign an event listener to a button, for example, and you press that button, the pressing of that button can get registered twice - the easiest and most obvious thing to do to get around this is to just set up a counter, and that button can only be pressed if the counter is 0. For example :

buttonCounter = 0

if event.phase == “up” and buttonCounter == 0 then

   buttonCounter = 1

   – here you just do the normal stuff for your button

end 

That should be a quick workaround.

Thanks

Your code is properly testing for the up phase, so it should be only running once.  Are you seeing the “ok success” message twice?

Rob

Did you perhaps put the code in both scenes and thus have 2 event listeners running?

to me it doesnt work except if i add “elseif buttonCounter == 1” but then what to add there in the elseif function?

by using buttonCounter, yeah it will change scene but then in the “other” scene, the buttonCounter is already “1” by now, so what should I add there? I tried  to use “global” buttonCounter and not local because using local function defeats the purpose of having buttonCounter.

I tried to use this code:

 if (event.keyName == "back" and event.phase == "up" and buttonCounter == 0) then buttonCounter = 1 storyboard.removeAll() storyboard.gotoScene("scene1", {time=250, effect="crossFade", params = options}) elseif (event.keyName == "back" and event.phase == "up" and buttonCounter == 1) then buttonCounter = 0 return true end

i dont know what I did wrong…

yes you are correct. the print message is always twice, so basically it is always “registered” twice as if i’m pressing the back button twice just like what sabir said. how to make the device know that i’m just pressing it once?

update: i dont mean the print message in that scene was printed twice, but once in that scene and once in another scene by just pressing it once.

let me say it like this:

i want to properly use the back button from scene3 -> scene2 -> scene1

i put the same onKeyEvent function in each scene. let’s say now I press the back button from scene3, it should move me to scene2 then “stop”, right? But the script recognize me as if i’m actually pressing the back button twice or even thrice, once in scene3, and once again in scene2. i noticed this after i make the print messages different in each scene.

yeah but i thought it doesnt matter because i use “storyboard.removeall”? plus the onKeyEvent is “local”.

also, i tried to add code like Runtime:removeEventListener( “key”, onKeyEvent ) in exitScene event but it doesnt change anything. same problem still happening.

I think a better way is to have this in a separate file that you require in your scene files or main.lua. Then it will never get executed 2x. So something like:

[lua]-- Name this file deviceKeys.lua

local storyboard = require(“storyboard”)

local function onKeyEvent( event )
    – Print which key was pressed down/up to the log.
    local message = “Key '” … event.keyName … "’ was pressed " … event.phase
    print( message )

    – Added the B as back key so you can test in simulator
    if (“back” == keyName and phase == “down”) or (“b” == keyName and phase == “down” and system.getInfo(“environment”) == “simulator”)  then

        storyboard.gotoScene(storyboard.getPrevious(), {time=250, effect=“crossFade”, params = options})
        print (" ok success")
        return true
    end

    return false
end

– Add the key event listener.
Runtime:addEventListener( “key”, onKeyEvent );

[/lua]

Put this in your main.lua and use the the single key listener for all scenes:

[lua]require(“deviceKeys.lua”)[/lua]

This is a good read, has a section on the back button: http://coronalabs.com/blog/2013/03/26/androidizing-your-mobile-app/

I’m not 100% sure this will fix all your problems, but its a good start :slight_smile:

I agree, you should only create these system wide handlers in your main.lua.  If it is scene dependent then you should start it in the enterScene (storyboard) or scene:show() (Composer) and remove it in exitScene (storyboard) scene:hide() (Composer).  You cannot start these in createScene (scene:create()) and expect a remove to get rid of them.  These are the types of handlers you have to start and stop on your own and the enter/exit (show/hide) are the only pairs of events guaranteed to fire for every scene.

Rob

sorry guys but i dont know how to put it in system wide handler in main.lua. yeah i have created that deviceKeys.lua and created the global function in main.lua:

deviceKeys = require "deviceKeys" 

but then what? What should I put in scene1/scene2/scene3 after this? Because as of now the “back” button just functioning like the original (when you press back, it just quit the app).

update: ok guys, it works! i just put the codes in main.lua so i dont need to create another lua file just for that.

now the only problem is just about the getPrevious() function that will bounce around like mentioned in that article: http://coronalabs.com/blog/2013/03/26/androidizing-your-mobile-app/

will read that one now. Thanks!

To sum up the bouncing between scenes issue.  .getPrevious() is not a history of previously visited scenes like say the back button in a web browser.  It literally is “get me the last scene that was shown”.   If you use it to back up a scene, then the previous scene was the original scene and you get in this loop of just cycling between the two scenes.

Rob

I have always noticed in Lua that if you assign an event listener to a button, for example, and you press that button, the pressing of that button can get registered twice - the easiest and most obvious thing to do to get around this is to just set up a counter, and that button can only be pressed if the counter is 0. For example :

buttonCounter = 0

if event.phase == “up” and buttonCounter == 0 then

   buttonCounter = 1

   – here you just do the normal stuff for your button

end 

That should be a quick workaround.

Thanks

Your code is properly testing for the up phase, so it should be only running once.  Are you seeing the “ok success” message twice?

Rob

Did you perhaps put the code in both scenes and thus have 2 event listeners running?

to me it doesnt work except if i add “elseif buttonCounter == 1” but then what to add there in the elseif function?

by using buttonCounter, yeah it will change scene but then in the “other” scene, the buttonCounter is already “1” by now, so what should I add there? I tried  to use “global” buttonCounter and not local because using local function defeats the purpose of having buttonCounter.

I tried to use this code:

 if (event.keyName == "back" and event.phase == "up" and buttonCounter == 0) then buttonCounter = 1 storyboard.removeAll() storyboard.gotoScene("scene1", {time=250, effect="crossFade", params = options}) elseif (event.keyName == "back" and event.phase == "up" and buttonCounter == 1) then buttonCounter = 0 return true end

i dont know what I did wrong…

yes you are correct. the print message is always twice, so basically it is always “registered” twice as if i’m pressing the back button twice just like what sabir said. how to make the device know that i’m just pressing it once?

update: i dont mean the print message in that scene was printed twice, but once in that scene and once in another scene by just pressing it once.

let me say it like this:

i want to properly use the back button from scene3 -> scene2 -> scene1

i put the same onKeyEvent function in each scene. let’s say now I press the back button from scene3, it should move me to scene2 then “stop”, right? But the script recognize me as if i’m actually pressing the back button twice or even thrice, once in scene3, and once again in scene2. i noticed this after i make the print messages different in each scene.

yeah but i thought it doesnt matter because i use “storyboard.removeall”? plus the onKeyEvent is “local”.

also, i tried to add code like Runtime:removeEventListener( “key”, onKeyEvent ) in exitScene event but it doesnt change anything. same problem still happening.

I think a better way is to have this in a separate file that you require in your scene files or main.lua. Then it will never get executed 2x. So something like:

[lua]-- Name this file deviceKeys.lua

local storyboard = require(“storyboard”)

local function onKeyEvent( event )
    – Print which key was pressed down/up to the log.
    local message = “Key '” … event.keyName … "’ was pressed " … event.phase
    print( message )

    – Added the B as back key so you can test in simulator
    if (“back” == keyName and phase == “down”) or (“b” == keyName and phase == “down” and system.getInfo(“environment”) == “simulator”)  then

        storyboard.gotoScene(storyboard.getPrevious(), {time=250, effect=“crossFade”, params = options})
        print (" ok success")
        return true
    end

    return false
end

– Add the key event listener.
Runtime:addEventListener( “key”, onKeyEvent );

[/lua]

Put this in your main.lua and use the the single key listener for all scenes:

[lua]require(“deviceKeys.lua”)[/lua]

This is a good read, has a section on the back button: http://coronalabs.com/blog/2013/03/26/androidizing-your-mobile-app/

I’m not 100% sure this will fix all your problems, but its a good start :slight_smile:

I agree, you should only create these system wide handlers in your main.lua.  If it is scene dependent then you should start it in the enterScene (storyboard) or scene:show() (Composer) and remove it in exitScene (storyboard) scene:hide() (Composer).  You cannot start these in createScene (scene:create()) and expect a remove to get rid of them.  These are the types of handlers you have to start and stop on your own and the enter/exit (show/hide) are the only pairs of events guaranteed to fire for every scene.

Rob