Remember to Cancel Timers When App Is In The Background

I had been working on my latest mobile game Hexium for quite a few months, and it was time to put it into the hands of some testers.  Everything seemed to be going well, but then one of the testers said that their Android phone was giving them a warning about it consuming too much battery power when it was in the background.  I had never seen this warning myself, despite already testing the app on a few Android devices of my own.  He showed me the screen, and sure enough the warning was on screen and looking fairly scary.  As an end user, my first instinct on seeing a warning like that for a casual game would be to simply uninstall the app.  This was bad.

I looked over my code and didn’t see anything that could be causing the problem.  I went to the Corona Labs web site and found this excellent article on performance and optimization.  However after implementing all of the tips, the tester was still receiving the warning.

Then I found it: a timer.  I had a timer that was firing every second while the game was running, to check to see if the user had earned a free life.  Of course this timer didn’t need to run while the app was in the background.  So I added some code to catch the applicationSuspended event and cancel the timer, and gave the updated build to the tester.

Success!! Android no longer complained about the app using battery while in the background!

Here is a block of code that contains just enough to show you what events were caught, and how I stopped and restarted the timer:

local free_life_timer

local onSystem = function(event)
    if event.type == "applicationExit" then
        -- Cancel the free life timer
        if free_life_timer ~= nil then
            timer.cancel(free_life_timer)
        end

    elseif event.type == "applicationSuspend" then
        -- Cancel the free life timer
        if free_life_timer ~= nil then
            timer.cancel(free_life_timer)
        end

    elseif event.type == "applicationResume" then
        - Start a new free life timer
        free_life_timer = timer.performWithDelay(1000, function()
            update_free_lives()
        end, 0)
    end
end

function scene:show( event )
    local phase = event.phase

    if ( phase == "will" ) then
        -- setup a system event listener
        Runtime:addEventListener( "system", onSystem )
        
    elseif ( phase == "did" ) then
        -- Start the free life timer
        free_life_timer = timer.performWithDelay(1000, function()
            update_free_lives()
        end, 0)
	end

end


function scene:hide( event )
    local phase = event.phase

    if ( phase == "will" ) then
        -- Cancel the free life timer
        timer.cancel(free_life_timer)
        Runtime:removeEventListener( "system", onSystem )
    end
end