Android device back button, need advice handling multiple presses

Hi again everyone.

I’m having problems handling the back button on the device being pressed twice quickly.

If you press the back button again while my code is still handling the first press it crashes the app.

I’ve added a global runtime listener (for obvious reasons) in my main.lua which checks for the back key press which then requires the “QuitAppExit” module which simply puts a message on the screen “Progress has been saved, really quit the game?” with a yes and a no button choice.

Here’s the part of the code in my main.lua that handles the devices back button.

local checkExit, quitApp, checkTimer, preCheck, removeQuitApp, reallyQuitApp, onKeyEvent local firstPress = false function onKeyEvent( event )    if ( "back" == event.keyName and event.phase == "down" ) then         if firstPress == false then               quitApp = require("QuitAppExit")               quitApp.activateButtons()               checkTimer = timer.performWithDelay( 500, preCheck, 1 )               firstPress = true         else               reallyQuitApp()         end       return true    end    return true end preCheck = function()     timer.cancel( checkTimer )     checkTimer = nil     Runtime:addEventListener( "enterFrame", checkExit ) end checkExit = function()     if quitApp then         if quitApp.noButton.isVisible == false then             quitApp.hideExit()             Runtime:removeEventListener( "enterFrame", checkExit )             checkTimer = timer.performWithDelay( 1000, removeQuitApp, 1 )         end         if quitApp.yesButton.isVisible == false then             quitApp.hideExit()             Runtime:removeEventListener( "enterFrame", checkExit )             checkTimer = timer.performWithDelay( 1000, reallyQuitApp, 1 )         end     end end removeQuitApp = function()     Runtime:removeEventListener( "key", onKeyEvent )     timer.cancel( checkTimer )     checkTimer = nil     quitApp.remVar()     package.loaded["QuitAppExit"] = nil     quitApp = nil end reallyQuitApp = function()     Runtime:removeEventListener( "key", onKeyEvent )     timer.cancel( checkTimer )     checkTimer = nil     quitApp.remVar()     package.loaded["QuitAppExit"] = nil     quitApp = nil     system.setIdleTimer( true )     package.loaded["physics"] = nil     physics = nil     package.loaded["socket"] = nil     socket = nil     package.loaded["loadsave"] = nil     loadsave = nil     display.setStatusBar(display.DefaultStatusBar)     storyboard.removeAll()     native.requestExit() end Runtime:addEventListener( "key", onKeyEvent )

I’ve experimented with different ways to try and stop the double tap on the back button crashing the app but I’m all out of ideas, has anybody here had this issue in the past and can give me some good advice?

Thanks!

Generally you would set a flag on the first press and maybe start a timer that would clear the flag after a set amount of time. If you get another event while the flag is active, ignore it.

Rob

Here’s mine:

local function exitOnBackKey(event) if event.phase == "down" and event.keyName == "back" then local onComplete = function(event) if event.action == "clicked" then local i = event.index if i == 2 then os.exit() end end end createAlert("MY GAME","ARE YOU SURE YOU WANT TO QUIT?",onComplete) return true end end Runtime:addEventListener("key", exitOnBackKey)

I don’t get a force-close or a crash. Do you want to try mine and see if you still get a crash?

Thanks Rob. I’ve tidied up the code in the original post, as you can see I do set a flag for the first and second press, on the second press it really quits the app without the user pressing the yes or no button that I display in the quitApp module, or that’s my intention if it worked.

By returning true in the onKeyEvent function this is supposed to tell the OS that I want to handle the back button on the device myself, am I doing it right?

Thanks Alex, I will start with your code and incorporate mine into it step by step, I will let you know how I get on.

I found the error(s) in my code.

What I was missing was on the second press of the back button the “reallyQuitApp” function is called and it tries to cancel the checkTimer which has already been cancelled in the “preCheck” function, so I put in an “if checkTimer then” statement and everything works.  I normally do if … then on my timers and transitions as a rule, silly mistake.

@Alex, thanks very much for your code, I didn’t use it in the end but it could have saved me a lot of work, so thanks. When I looked up os.exit() Corona says it’s not a good idea to use it as it can look like the app stopped abruptly, they recommend using native.requestExit() instead, just a thought.

Generally you would set a flag on the first press and maybe start a timer that would clear the flag after a set amount of time. If you get another event while the flag is active, ignore it.

Rob

Here’s mine:

local function exitOnBackKey(event) if event.phase == "down" and event.keyName == "back" then local onComplete = function(event) if event.action == "clicked" then local i = event.index if i == 2 then os.exit() end end end createAlert("MY GAME","ARE YOU SURE YOU WANT TO QUIT?",onComplete) return true end end Runtime:addEventListener("key", exitOnBackKey)

I don’t get a force-close or a crash. Do you want to try mine and see if you still get a crash?

Thanks Rob. I’ve tidied up the code in the original post, as you can see I do set a flag for the first and second press, on the second press it really quits the app without the user pressing the yes or no button that I display in the quitApp module, or that’s my intention if it worked.

By returning true in the onKeyEvent function this is supposed to tell the OS that I want to handle the back button on the device myself, am I doing it right?

Thanks Alex, I will start with your code and incorporate mine into it step by step, I will let you know how I get on.

I found the error(s) in my code.

What I was missing was on the second press of the back button the “reallyQuitApp” function is called and it tries to cancel the checkTimer which has already been cancelled in the “preCheck” function, so I put in an “if checkTimer then” statement and everything works.  I normally do if … then on my timers and transitions as a rule, silly mistake.

@Alex, thanks very much for your code, I didn’t use it in the end but it could have saved me a lot of work, so thanks. When I looked up os.exit() Corona says it’s not a good idea to use it as it can look like the app stopped abruptly, they recommend using native.requestExit() instead, just a thought.