Multiple Key Listeners

I have put this into scene creation:

Runtime:addEventListener("key",keylistener)

And this into scene destroying:

function scene:destroy() local group = self.view group:removeSelf() Runtime:removeEventListener("key",keylistener) end

But this listener is never removing and start multipling every time I reload the scene.

scene:destroy is not always called when a scene is hidden. It is only called upon a command or when more memory is needed.

One of two options is you can move the Runtime:removeEventListener code to scene:hide.  Or you can turn on recycling:

composer.recycleOnSceneChange = true

Still not working, even if I put this in scene creation:

Runtime:removeEventListener("key",keylistener) Runtime:addEventListener("key",keylistener)

Can you post your updated code?

composer.recycleOnSceneChange = true --scene:create local function keylistener(event) if event.keyName == "back" and event.phase == "up" then if composer.getVariable("place") == "challengepause" then local function exitgamelistener(event) if event.action == "clicked" and event.index == 1 then native.requestExit() end end native.showAlert("Exit Game","Are you sure you want to exit this game?",{"Yes","No"},exitgamelistener) return true elseif composer.getVariable("place") == "challenge" then tearready = false pause.isVisible = false unpause.isVisible = true achievements.isVisible = true leaderboards.isVisible = true if settings.sounds then soundson.isVisible = true else soundsoff.isVisible = true end score.isVisible = false highscore.isVisible = false if stage == "game" then for i = 1,timers do timer.pause(timerid[i]) end for i = 1,actualtear - 1 do transition.pause(tear[i]) tear[i].isVisible = false end end composer.setVariable("place","challengepause") return true elseif composer.getVariable("place") == "challengegameover" then pause.isVisible = false unpause.isVisible = true achievements.isVisible = true leaderboards.isVisible = true if settings.sounds then soundson.isVisible = true else soundsoff.isVisible = true end score.isVisible = false highscore.isVisible = false composer.setVariable("place","challengepause") return true end end    return false end   Runtime:addEventListener("key",keylistener)   function scene:destroy() local group = self.view group:removeSelf() Runtime:removeEventListener("key",keylistener) end

This looks like a scope issue.   Your keylistener function is local to scene:create, and therefore not accessible from scene:destroy.  Try to declare it first outside of any functions like:

composer.recycleOnSceneChange = true local keylistener scene:create() function keylistener(event) --remove local here ...

Works now, thank you.

Generally speaking, I would not put a “key” listener in scene:create() and wait until scene:destroy() to clean up. Instead I would put them in scene:show() in the “did” phase and scene:hide() in the “will” phase. This way they are enabled after the scene is on the screen and disable before the scene leaves the screen. These two functions are guaranteed to run at a predictable time. You really don’t want two key listeners running at the same time.

Rob

scene:destroy is not always called when a scene is hidden. It is only called upon a command or when more memory is needed.

One of two options is you can move the Runtime:removeEventListener code to scene:hide.  Or you can turn on recycling:

composer.recycleOnSceneChange = true

Still not working, even if I put this in scene creation:

Runtime:removeEventListener("key",keylistener) Runtime:addEventListener("key",keylistener)

Can you post your updated code?

composer.recycleOnSceneChange = true --scene:create local function keylistener(event) if event.keyName == "back" and event.phase == "up" then if composer.getVariable("place") == "challengepause" then local function exitgamelistener(event) if event.action == "clicked" and event.index == 1 then native.requestExit() end end native.showAlert("Exit Game","Are you sure you want to exit this game?",{"Yes","No"},exitgamelistener) return true elseif composer.getVariable("place") == "challenge" then tearready = false pause.isVisible = false unpause.isVisible = true achievements.isVisible = true leaderboards.isVisible = true if settings.sounds then soundson.isVisible = true else soundsoff.isVisible = true end score.isVisible = false highscore.isVisible = false if stage == "game" then for i = 1,timers do timer.pause(timerid[i]) end for i = 1,actualtear - 1 do transition.pause(tear[i]) tear[i].isVisible = false end end composer.setVariable("place","challengepause") return true elseif composer.getVariable("place") == "challengegameover" then pause.isVisible = false unpause.isVisible = true achievements.isVisible = true leaderboards.isVisible = true if settings.sounds then soundson.isVisible = true else soundsoff.isVisible = true end score.isVisible = false highscore.isVisible = false composer.setVariable("place","challengepause") return true end end    return false end   Runtime:addEventListener("key",keylistener)   function scene:destroy() local group = self.view group:removeSelf() Runtime:removeEventListener("key",keylistener) end

This looks like a scope issue.   Your keylistener function is local to scene:create, and therefore not accessible from scene:destroy.  Try to declare it first outside of any functions like:

composer.recycleOnSceneChange = true local keylistener scene:create() function keylistener(event) --remove local here ...

Works now, thank you.

Generally speaking, I would not put a “key” listener in scene:create() and wait until scene:destroy() to clean up. Instead I would put them in scene:show() in the “did” phase and scene:hide() in the “will” phase. This way they are enabled after the scene is on the screen and disable before the scene leaves the screen. These two functions are guaranteed to run at a predictable time. You really don’t want two key listeners running at the same time.

Rob