Event Listener
Before you can start monitoring system events in your Corona app, you need to set up a listener function, and add a “system” event listener. If you’re not familiar with events in Corona, I suggest you read The Corona Event Model Explained document before continuing.
The code below—commonly placed at the end of main.lua—shows how to setup your event listener, and also add it to the global Runtime object (the only object that can listen for “system” events).
local function onSystemEvent( event )
-- Test for different event types here
end
Runtime:addEventListener( "system", onSystemEvent )
applicationStart
local function onSystemEvent( event )
if event.type == "applicationStart" then
do_something()
end
end
The above code example shows how to test for the “applicationStart” event type in your system event listener.
You app will receive an “applicationStart” event when your app launches (from a closed/cold state, not a suspended state), and after the code in main.lua has executed.
applicationExit
local function onSystemEvent( event )
if event.type == "applicationExit" then
do_something()
end
end
The “applicationExit” system event is dispatched just prior to your app quitting (e.g. not suspending, but fully closing). This can occur from the user explicitly, or if the operating system’s task manager tells the app to close for whatever reason (usually due to your app being the least recently used, in low memory situation).
Things that this event is most commonly used for is to do any last-minute data saving, closing open database connections, etc.
Update: there are many circumstances in which the “applicationExit” system event wont be dispatched so don’t rely on it for important application logic. For example, if the user force-closes the application or the battery is removed from the device without properly shutting it down. Applications on mobile devices generally have to assume that they may just stop at any point and will be restarted from scratch.
applicationSuspend
local function onSystemEvent( event )
if event.type == "applicationSuspend" then
do_something()
end
end
I touched on this briefly already, but if the user receives a phone call, or anything happens that causes the user to have to switch out of your app on their device, or if the user presses the “power” button and puts their device to sleep, your app will go into a suspended state (but will not quit).
Prior to going into this suspended state, an “applicationSuspend” event will be dispatched, which gives you a chance to do things such as pause the game (so the user will be at the pause screen when they come back, instead of on the verge of being defeated!), mark the time (for any time-tracking functionality), pause/stop any timers and/or transitions, etc.
applicationResume
local function onSystemEvent( event )
if event.type == "applicationResume" then
do_something()
end
end
Speaking of your app being suspended, you also have a chance to “do something” whenever your app comes back from the suspended state, which is where the “applicationResume” event comes in.
Putting it all together
local function onSystemEvent( event )
if event.type == "applicationStart" then
-- this block executed when application launches (after main.lua)
elseif event.type == "applicationExit" then
-- this block executed just prior to the app quitting
-- OS closes least recently used app, user explicitly quits, etc.
elseif event.type == "applicationSuspend" then
-- this block executed when app goes into "suspend" state
-- e.g. user receives phone call, presses home button, etc.
elseif event.type == "applicationResume" then
-- this block executed when app resumes from "suspend" state
-- e.g. user goes back into app (while it is still running in bg)
end
end
Runtime:addEventListener( "system", onSystemEvent )
The above is a barebones system event listener, which you can actually use as a template. Of course, what you put into the individual if/else blocks is completely up to your app.
If you pay close attention, you’ll notice almost every commercial-grade application or game makes use of one or more of the system events mentioned in this tutorial—and for good reason: they are not only absolutely necessary for some apps, but they can be leveraged to enhance the user experience tremendously for many apps.
Before releasing your app, take a moment and think to yourself, What should my app do when it goes into suspended mode? When it comes back? Before it closes? And you’ll likely find a way to make your app even better, or perhaps solve a problem you didn’t know the solution to prior to learning about system events.




DW
Please, please don’t stop these tutorials. They are very beneficial!
Alex
Another great tutorial Jon! Thanks a lot!
Mo
PERFECT! Exactly what I needed. Two questions if i may:
1- If understand correctly, I need to put the code above only at the bottom of main.lua and nowhere else. Correct? (i am using Director and have multiple modules)
2- In my gameScreen.lua module (where the game play is) I have a PAUSE button and an attached listener function. This function pause the physics, sound..How do I pause the game say when the player press the home button? The pause function is not in scope in the main.lua module. Do i need to make my pause function in gameScreen.lua global?
I hope I making sense but in event, thank you so much Jon for making hard stuff easier to understand every week. Love it!
Mo
(LairdGames)
dataskrekk
Can you give a meaningful example for applicationStart, i.e. how is this different from just starting the app?
Max
@Mo
1 – Yes, but all your function calls have to go there too.
2 – Yes, the easiest solution is to make it global.
Luis Jose Regis
You are just reading my mind, i was just about to start developing that feature on Spermin.
Thanks!
Mo
Hey thanks Max! Not sure i understand you correctly.
1- What do you mean by “all your function calls have to go there too”?
2- I thought “global” was a bad word!?
Thanks again.
Mo
Mo
Maybe a small example with 2 modules using Storyboard would help. I am using director but I am sure I can figure out what to do even with a storyboard example. Thank you!
Mo
Perry
@Mo
I had that question as well. There was a similar tutorial awhile back on mobile tuts. The author of that article suggested removing the runtime event listener for system event functions when cleaning up a scene. To me, that sounded like the system event function (example above) would go in each module.
Mo
@Perry
That will make sense to me too because it would avoid having to deal global functions and simplify the code since you will deal with game pause for instance in the module where the game is actually running.
Maybe Jon can show us an implementation example…
Thanks Perry.
Mo
Mo
@Perry: I found this on the forum which seems to in “part” answer our question:
http://developer.anscamobile.com/forum/2012/01/02/game-restarted-pressing-home-button-ios
The only “problem” it seems that it seems that they use the “onSystemEvent( event )” on both main.lua and game.lua module. Not sure if it is a problem?
Mo
Perry
@Mo
Thanks for the link, very helpful, but the thread dies out just as it was getting good
I’m not sure how that would affect things. You would remove the listener in the module on exit but it seems like the runtime listener in main.lua would always be running (good or bad?).
Perry
Mo
@Perry. I know what you mean. Jon, Max? Perry and I are dying in here…ha! ha!
Mo
Jonathan Beebe
The easiest option would be to add the system event listener in main.lua, and have your pause function global.
Remember, it’s not “evil” to have global functions, you just have to weight out in your mind when it is best to avoid them, and best to use them. Everything in Lua is a table lookup (no matter whether it is local or global), it’s just that global look-ups generally take longer because they cover a wider scope.
However, to ease your mind, here’s what you can do. Assuming your actual game is in the “enterScene” listener function of your “game” scene. At the top of the “enterScene” event, you could do this:
local pause = pauseFunction
“pauseFunction” in the example above would be the ‘global’ pause function that needs to be accessed several places. Now whenever you call pause() from within that block, you’ll still be calling the original function, but this time the look-up is using the local reference within the block instead of having to find the function in the global space.
Of course, that’s an example—your actual game code that needs the function might be in a different function (not within the enterScene listener). But the point is, you can localize a global function within the block that it’s needed, and whenever you call the local reference, the look-up is local rather than global—if you’re dealing with a function that needs to be executed as fast as possible (I could see why ‘pause’ might fit into that category).
Mo
Hello Jon.
THANK YOU! I am afraid i am still confused.OK here a really concrete example:
What if I have this on my game.lua sceen (which pause the game if the btPause button is pressed):
————————————————————-
local function pauseGame()
if fxOn then audio.play( tapSound ) end
isGameActive = false
btPause.isVisible = false
btExit.isVisible = true
btResume.isVisible = true
physics.pause()
Particles.Freeze()
audio.pause(gameMusic)
timer.pause(rockTimer)
end
end
–
local function btPauseTouch (event) —- listener for a pause button in gameScreen.lua
local phase = event.phase
if phase == “release” then
pauseGame()
end
return true
end
—————————————–
Would I need to simply make pauseGame() a global function (remove the LOCAL in front of it in gameScreen.lua)? And then simply call that function from main.lua like this:
local function onSystemEvent( event )
if event.type == “applicationResume” then
pauseGame()
end
end
Sorry for being “dense” today:(
Mo
ps: By the way, thanks to you and some others in the forum, I am starting to get comfortable with globals. They no longer scare me late at night:)
Mo
oops! I meant “”applicationSuspend” not “applicationResume”…sorry!
Mo.
Jonathan Beebe
@Mo: If you remove “local” from your pauseGame() function definition, then it will be global. The problem I foresee you running into is if the app gets an “applicationSuspend” event before your pauseGame() function is defined (e.g. the user gets a phone call on the main menu, before they even get to game.lua).
What you can do is check if it exists before attempting to call it. So in your system event listener, it would look something like this:
local function onSystemEvent( event )
if event.type == "applicationSuspend" then
if _G.pauseGame then
_G.pauseGame()
end
end
end
Runtime:addEventListener( "system", onSystemEvent )
Also, I normally prefix globals with _G. for two reasons: 1) so when I’m looking back at my code I can clearly see what is global and what is not and 2) it prevents you from accidentally overriding a local variable within scope that uses the same name (and other odd situations like that).
So in other words, I would just use _G.pauseGame when defining the function, and also when calling it. _G. is a reference to the “global” Lua table that the entire Lua environment resides in.
Mo
@Jon: PERFECT! One more question if I may (I think Perry had the same one)
Would you put your code:
local function onSystemEvent( event )
–
end
ONLY at the bottom of main.lua and no other place (no other modules)?
Thanks again for your patience with me today. And please keep these wonderful blog posts coming!
Mo
Delwing
IMHO it depends. I have some code that I want to be run only while ceratin window is shown. Instead of checking active window etc. I just add event listener on creation of this window and remove it after it is done showing – everything handled in one module.
NithinMani
Thnx guys……….
Perry
I updated the “applicationExit” section with some important info about when it might get called.