Error when leaving scene with map

Hello,

I have a scene that shows a map and and I have a location handler that centers the map each time. When I leave the scene I get this error:

Attempt to call method ‘setCenter’ (a nil value)

I try removing the event listener for the location handler but it may be wrong. Here is code for the parts being used for this. Any help would be appreciated!

Thanks,

Warren

Location Handler Code:   (works fine)

local locationHandler = function( event ) -- Check for error (user may have turned off location services) if ( event.errorCode ) then native.showAlert( "GPS Location Error", event.errorMessage, {"OK"} ) print( "Location error: " .. tostring( event.errorMessage ) ) else if ( myMap == nil ) then return end lat1 = event.latitude lon1 = event.longitude if isCentered == "N" then isCentered = "Y" print("Map Centered") if myMap then myMap:setRegion( lat1, lon1, 0.01, 0.01, true ) end end if chkRefresh.isOn == true then if myMap then myMap:setCenter( lat1, lon1, true ) end isCentered = "Y" end end end

Starting the event listener:

Runtime:addEventListener( "location", locationHandler )

Removing the listener before going to the next scene:

Runtime:removeEventListener( "location", locationHandler )

Where are you defining locationHandler and where are you actually calling the removeEventListener?

Rob

Here is all of the code for the scene.

Thanks

--------------------------------------------------------------------------------- -- -- scene.lua -- --------------------------------------------------------------------------------- local composer = require( "composer" ) local scene = composer.newScene() local widget = require( "widget" ) require "sqlite3" local json = require ("json") local Top7, Bottom7, Height7, Width7, Left7, Right7, bar, lblTitle, btnMenu, myMap, chkRefresh, lblRefresh, btnHome local lat1, lon1, lat2, lon2, isCentered lat1 = 0 lon1 = 0 isCentered = "N" local timerID, timerIDMap --------------------------------------------------------------------------------- Height7 = display.actualContentHeight local N1 = Height7 - 960 if N1 \< 0 then N1 = 0 end Top7 = 0 - (N1 / 2) Bottom7 = 960 + (N1 / 2) N1 = display.topStatusBarContentHeight if N1 \< 20 then N1 = 26 end Top7 = Top7 + N1 Width7 = display.actualContentWidth local N1 = Width7 - 640 if N1 \< 0 then N1 = 0 end Left7 = 0 - (N1 / 2) Right7 = 640 + (N1 / 2) ----------------------------------------------------------------------------------------- local function RemoveAll() Runtime:removeEventListener( "location", locationHandler ) timer.cancel(timerID) timer.cancel(timerIDMap) Runtime:removeEventListener( "key", onKeyEvent ) bar:removeSelf() lblTitle:removeSelf() btnMenu:removeSelf() myMap:removeSelf() chkRefresh:removeSelf() lblRefresh:removeSelf() btnHome:removeSelf() composer.removeScene( "sceneMap" ) end local function onKeyEvent( event ) local phase = event.phase local keyName = event.keyName print( event.phase, event.keyName ) if ( "back" == keyName and phase == "up" ) then RemoveAll() composer.gotoScene( "scene1" ) end if ( keyName == "volumeUp" and phase == "down" ) then local masterVolume = audio.getVolume() print( "volume:", masterVolume ) if ( masterVolume \< 1.0 ) then masterVolume = masterVolume + 0.1 audio.setVolume( masterVolume ) end return true elseif ( keyName == "volumeDown" and phase == "down" ) then local masterVolume = audio.getVolume() print( "volume:", masterVolume ) if ( masterVolume \> 0.0 ) then masterVolume = masterVolume - 0.1 audio.setVolume( masterVolume ) end return true end return true end --------------------------------------------------------------------------------- local function btnHomeButtonEvent( event ) if ("ended" == event.phase ) then RemoveAll() timer.cancel(timerID) Runtime:removeEventListener( "location", locationHandler ) Runtime:removeEventListener( "key", onKeyEvent ) composer.gotoScene( "scene1" ) end end local function mapLocationListener(event) print("map tapped latitude: ", event.latitude) print("map tapped longitude: ", event.longitude) end local function AddMapMarker( event ) if ( myMap == nil ) then return end if lat1 == nil or lat1 == 0 then return end myMap:removeAllMarkers() local options = { title = "Your Current Location", imageFile = "marker1.png", } myMap:addMarker( lat1, lon1, options ) end local locationHandler = function( event ) -- Check for error (user may have turned off location services) if ( event.errorCode ) then native.showAlert( "GPS Location Error", event.errorMessage, {"OK"} ) print( "Location error: " .. tostring( event.errorMessage ) ) else if ( myMap == nil ) then return end lat1 = event.latitude lon1 = event.longitude if isCentered == "N" then isCentered = "Y" print("Map Centered") if myMap then myMap:setRegion( lat1, lon1, 0.01, 0.01, true ) end end if chkRefresh.isOn == true then if myMap then myMap:setCenter( lat1, lon1, true ) end isCentered = "Y" end end end local function showAlert( event ) lblTitle.text = "Boundry Violated!!!" media.playSound( "alert.mp3" ) end local function networkListener( event ) if ( event.isError ) then print( "Network error!") --lblStatus1.text = "A network error has occured. Please make sure you have a network connection on your device and try again." else lblTitle.text = "Data returned" print( "Data received" ) myNewData = event.response local myTable = json.decode(myNewData) Results = #myTable.results for i=1,Results do local County2 = myTable.results[i].locations[1].adminArea4 local State2 = myTable.results[i].locations[1].adminArea3 if County2 ~= "" and County2 ~= nil and State2 ~= "" and State2 ~= nil then if composer.getVariable( "boundry" ) == "s" then local State3 = composer.getVariable( "State" ) if State2 ~= State3 then showAlert() end end if composer.getVariable( "boundry" ) == "c" then local County3 = composer.getVariable( "County" ) if County2 ~= County3 then showAlert() end end end end lblText2.isVisible = false lblWait.isVisible = false end end local function checkBoundry( event ) if lat1 ~= nil and lat1 ~= 0 and lon1 ~= nil and lon1 ~= 0 then network.request( "http://open.mapquestapi.com/geocoding/v1/reverse?key=Fmjtd%7Cluur2hu8ll%2Cb5%3Do5-9wa0df&json={location:{latLng:{lat:" .. lat1 .. ",lng:" .. lon1 .. "}}}", "GET", networkListener ) else lblTitle.text = "No boundry found" end end local function createTimer() timerID = timer.performWithDelay(15000, checkBoundry, 0) end local function createMapTimer() timerIDMap = timer.performWithDelay( 6000, AddMapMarker, 0 ) end local function onRefreshPress( event ) local switch = event.target if switch.isOn == true then chkState:setState( { isOn=false, isAnimated=true } ) end end function scene:create( event ) local sceneGroup = self.view -- Called when the scene's view does not exist -- -- INSERT code here to initialize the scene -- e.g. add display objects to 'sceneGroup', add touch listeners, etc end function scene:show( event ) local sceneGroup = self.view local phase = event.phase if phase == "will" then -- Called when the scene is still off screen and is about to move on screen display.setDefault( "background", 1, 1, 1 ) display.setStatusBar(display.DefaultStatusBar) display.setDefault( "anchorX", 0.5 ) display.setDefault( "anchorY", 0.5 ) bar = display.newImageRect( "images/header3.png", Width7, 85 ) bar.anchorX = 0 bar.anchorY = 0 bar.x = Left7 bar.y = Top7 lblTitle = display.newText( "App Name", 320, Top7 + 24, native.systemFontBold, 40 ) lblTitle:setFillColor( 1, 10, 1 ) lblTitle.anchorX = 0.5 lblTitle.anchorY = 0 btnMenu = widget.newButton { width = 87, height = 85, defaultFile = "images/btnMenu.png", overFile = "images/btnMenu.png", label = "", onEvent = btnMenuButtonEvent } btnMenu.anchorX = 0 btnMenu.anchorY = 0 btnMenu.y = Top7 btnMenu.x = Left7 Top7 = Top7 + 85 myMap = native.newMapView( Left7, Top7, Width7, Bottom7 - Top7 - 115 ) myMap.anchorX = 0 myMap.anchorY = 0 myMap.x = Left7 myMap.y = Top7 if ( myMap ) then -- Display a normal map with vector drawings of the streets. -- Other mapType options are "satellite" and "hybrid". myMap.mapType = "normal" end btnHome = widget.newButton { width = 175, height = 73, defaultFile = "images/btnHome5.png", overFile = "images/btnHome6.png", label = "", onEvent = btnHomeButtonEvent } btnHome.anchorX = 0 btnHome.anchorY = 0 btnHome.y = Bottom7 - 95 btnHome.x = 30 chkRefresh = widget.newSwitch { left = 240, top = Bottom7 - 95, width = 80, height = 80, style = "checkbox", id = "chkRefresh", onPress = onRefreshPress, initialSwitchState = true, } lblRefresh = display.newText( "Auto-refresh map", 320, Bottom7 - 95 + 11, native.systemFontBold, 30 ) lblRefresh:setFillColor( 0, 0, 0 ) lblRefresh.anchorX = 0 lblRefresh.anchorY = 0 elseif phase == "did" then -- Called when the scene is now on screen -- -- INSERT code here to make the scene come alive -- e.g. start timers, begin animation, play audio, etc Runtime:addEventListener( "location", locationHandler ) Runtime:addEventListener( "key", onKeyEvent ) --timer.performWithDelay( 3000, AddMapMarker, 0 ) createTimer() createMapTimer() end end function scene:hide( event ) local sceneGroup = self.view local phase = event.phase if event.phase == "will" then -- Called when the scene is on screen and is about to move off screen -- -- INSERT code here to pause the scene -- e.g. stop timers, stop animation, unload sounds, etc.) elseif phase == "did" then -- Called when the scene is now off screen end end function scene:destroy( event ) local sceneGroup = self.view -- Called prior to the removal of scene's "view" (sceneGroup) -- -- INSERT code here to cleanup the scene -- e.g. remove display objects, remove touch listeners, save state, etc end --------------------------------------------------------------------------------- -- Listener setup scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) --------------------------------------------------------------------------------- return scene

It seems like it is not removing the event listener for the location handler. I even check if the map object is valid first before calling setCenter.

This block of code

local function btnHomeButtonEvent( event ) &nbsp;&nbsp;&nbsp; if ("ended" == event.phase ) then &nbsp;&nbsp; &nbsp;RemoveAll() &nbsp;&nbsp; &nbsp;timer.cancel(timerID) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Runtime:removeEventListener( "location", locationHandler ) &nbsp;&nbsp; &nbsp;Runtime:removeEventListener( "key", onKeyEvent ) &nbsp;&nbsp; &nbsp;composer.gotoScene( "scene1" ) &nbsp;&nbsp;&nbsp; end end

Needs to be below the locationHandler function.  Corona SDK is a one pass compiler and at the point you have the code for the removeEventListener() in the function above, locationHandler is likely nil.

Rob

Thanks. Actually I am using the Back button to go back to the home page scene1.

It’s still a matter of code order and when things get values.

Rob

Where are you defining locationHandler and where are you actually calling the removeEventListener?

Rob

Here is all of the code for the scene.

Thanks

--------------------------------------------------------------------------------- -- -- scene.lua -- --------------------------------------------------------------------------------- local composer = require( "composer" ) local scene = composer.newScene() local widget = require( "widget" ) require "sqlite3" local json = require ("json") local Top7, Bottom7, Height7, Width7, Left7, Right7, bar, lblTitle, btnMenu, myMap, chkRefresh, lblRefresh, btnHome local lat1, lon1, lat2, lon2, isCentered lat1 = 0 lon1 = 0 isCentered = "N" local timerID, timerIDMap --------------------------------------------------------------------------------- Height7 = display.actualContentHeight local N1 = Height7 - 960 if N1 \< 0 then N1 = 0 end Top7 = 0 - (N1 / 2) Bottom7 = 960 + (N1 / 2) N1 = display.topStatusBarContentHeight if N1 \< 20 then N1 = 26 end Top7 = Top7 + N1 Width7 = display.actualContentWidth local N1 = Width7 - 640 if N1 \< 0 then N1 = 0 end Left7 = 0 - (N1 / 2) Right7 = 640 + (N1 / 2) ----------------------------------------------------------------------------------------- local function RemoveAll() Runtime:removeEventListener( "location", locationHandler ) timer.cancel(timerID) timer.cancel(timerIDMap) Runtime:removeEventListener( "key", onKeyEvent ) bar:removeSelf() lblTitle:removeSelf() btnMenu:removeSelf() myMap:removeSelf() chkRefresh:removeSelf() lblRefresh:removeSelf() btnHome:removeSelf() composer.removeScene( "sceneMap" ) end local function onKeyEvent( event ) local phase = event.phase local keyName = event.keyName print( event.phase, event.keyName ) if ( "back" == keyName and phase == "up" ) then RemoveAll() composer.gotoScene( "scene1" ) end if ( keyName == "volumeUp" and phase == "down" ) then local masterVolume = audio.getVolume() print( "volume:", masterVolume ) if ( masterVolume \< 1.0 ) then masterVolume = masterVolume + 0.1 audio.setVolume( masterVolume ) end return true elseif ( keyName == "volumeDown" and phase == "down" ) then local masterVolume = audio.getVolume() print( "volume:", masterVolume ) if ( masterVolume \> 0.0 ) then masterVolume = masterVolume - 0.1 audio.setVolume( masterVolume ) end return true end return true end --------------------------------------------------------------------------------- local function btnHomeButtonEvent( event ) if ("ended" == event.phase ) then RemoveAll() timer.cancel(timerID) Runtime:removeEventListener( "location", locationHandler ) Runtime:removeEventListener( "key", onKeyEvent ) composer.gotoScene( "scene1" ) end end local function mapLocationListener(event) print("map tapped latitude: ", event.latitude) print("map tapped longitude: ", event.longitude) end local function AddMapMarker( event ) if ( myMap == nil ) then return end if lat1 == nil or lat1 == 0 then return end myMap:removeAllMarkers() local options = { title = "Your Current Location", imageFile = "marker1.png", } myMap:addMarker( lat1, lon1, options ) end local locationHandler = function( event ) -- Check for error (user may have turned off location services) if ( event.errorCode ) then native.showAlert( "GPS Location Error", event.errorMessage, {"OK"} ) print( "Location error: " .. tostring( event.errorMessage ) ) else if ( myMap == nil ) then return end lat1 = event.latitude lon1 = event.longitude if isCentered == "N" then isCentered = "Y" print("Map Centered") if myMap then myMap:setRegion( lat1, lon1, 0.01, 0.01, true ) end end if chkRefresh.isOn == true then if myMap then myMap:setCenter( lat1, lon1, true ) end isCentered = "Y" end end end local function showAlert( event ) lblTitle.text = "Boundry Violated!!!" media.playSound( "alert.mp3" ) end local function networkListener( event ) if ( event.isError ) then print( "Network error!") --lblStatus1.text = "A network error has occured. Please make sure you have a network connection on your device and try again." else lblTitle.text = "Data returned" print( "Data received" ) myNewData = event.response local myTable = json.decode(myNewData) Results = #myTable.results for i=1,Results do local County2 = myTable.results[i].locations[1].adminArea4 local State2 = myTable.results[i].locations[1].adminArea3 if County2 ~= "" and County2 ~= nil and State2 ~= "" and State2 ~= nil then if composer.getVariable( "boundry" ) == "s" then local State3 = composer.getVariable( "State" ) if State2 ~= State3 then showAlert() end end if composer.getVariable( "boundry" ) == "c" then local County3 = composer.getVariable( "County" ) if County2 ~= County3 then showAlert() end end end end lblText2.isVisible = false lblWait.isVisible = false end end local function checkBoundry( event ) if lat1 ~= nil and lat1 ~= 0 and lon1 ~= nil and lon1 ~= 0 then network.request( "http://open.mapquestapi.com/geocoding/v1/reverse?key=Fmjtd%7Cluur2hu8ll%2Cb5%3Do5-9wa0df&json={location:{latLng:{lat:" .. lat1 .. ",lng:" .. lon1 .. "}}}", "GET", networkListener ) else lblTitle.text = "No boundry found" end end local function createTimer() timerID = timer.performWithDelay(15000, checkBoundry, 0) end local function createMapTimer() timerIDMap = timer.performWithDelay( 6000, AddMapMarker, 0 ) end local function onRefreshPress( event ) local switch = event.target if switch.isOn == true then chkState:setState( { isOn=false, isAnimated=true } ) end end function scene:create( event ) local sceneGroup = self.view -- Called when the scene's view does not exist -- -- INSERT code here to initialize the scene -- e.g. add display objects to 'sceneGroup', add touch listeners, etc end function scene:show( event ) local sceneGroup = self.view local phase = event.phase if phase == "will" then -- Called when the scene is still off screen and is about to move on screen display.setDefault( "background", 1, 1, 1 ) display.setStatusBar(display.DefaultStatusBar) display.setDefault( "anchorX", 0.5 ) display.setDefault( "anchorY", 0.5 ) bar = display.newImageRect( "images/header3.png", Width7, 85 ) bar.anchorX = 0 bar.anchorY = 0 bar.x = Left7 bar.y = Top7 lblTitle = display.newText( "App Name", 320, Top7 + 24, native.systemFontBold, 40 ) lblTitle:setFillColor( 1, 10, 1 ) lblTitle.anchorX = 0.5 lblTitle.anchorY = 0 btnMenu = widget.newButton { width = 87, height = 85, defaultFile = "images/btnMenu.png", overFile = "images/btnMenu.png", label = "", onEvent = btnMenuButtonEvent } btnMenu.anchorX = 0 btnMenu.anchorY = 0 btnMenu.y = Top7 btnMenu.x = Left7 Top7 = Top7 + 85 myMap = native.newMapView( Left7, Top7, Width7, Bottom7 - Top7 - 115 ) myMap.anchorX = 0 myMap.anchorY = 0 myMap.x = Left7 myMap.y = Top7 if ( myMap ) then -- Display a normal map with vector drawings of the streets. -- Other mapType options are "satellite" and "hybrid". myMap.mapType = "normal" end btnHome = widget.newButton { width = 175, height = 73, defaultFile = "images/btnHome5.png", overFile = "images/btnHome6.png", label = "", onEvent = btnHomeButtonEvent } btnHome.anchorX = 0 btnHome.anchorY = 0 btnHome.y = Bottom7 - 95 btnHome.x = 30 chkRefresh = widget.newSwitch { left = 240, top = Bottom7 - 95, width = 80, height = 80, style = "checkbox", id = "chkRefresh", onPress = onRefreshPress, initialSwitchState = true, } lblRefresh = display.newText( "Auto-refresh map", 320, Bottom7 - 95 + 11, native.systemFontBold, 30 ) lblRefresh:setFillColor( 0, 0, 0 ) lblRefresh.anchorX = 0 lblRefresh.anchorY = 0 elseif phase == "did" then -- Called when the scene is now on screen -- -- INSERT code here to make the scene come alive -- e.g. start timers, begin animation, play audio, etc Runtime:addEventListener( "location", locationHandler ) Runtime:addEventListener( "key", onKeyEvent ) --timer.performWithDelay( 3000, AddMapMarker, 0 ) createTimer() createMapTimer() end end function scene:hide( event ) local sceneGroup = self.view local phase = event.phase if event.phase == "will" then -- Called when the scene is on screen and is about to move off screen -- -- INSERT code here to pause the scene -- e.g. stop timers, stop animation, unload sounds, etc.) elseif phase == "did" then -- Called when the scene is now off screen end end function scene:destroy( event ) local sceneGroup = self.view -- Called prior to the removal of scene's "view" (sceneGroup) -- -- INSERT code here to cleanup the scene -- e.g. remove display objects, remove touch listeners, save state, etc end --------------------------------------------------------------------------------- -- Listener setup scene:addEventListener( "create", scene ) scene:addEventListener( "show", scene ) scene:addEventListener( "hide", scene ) scene:addEventListener( "destroy", scene ) --------------------------------------------------------------------------------- return scene

It seems like it is not removing the event listener for the location handler. I even check if the map object is valid first before calling setCenter.

This block of code

local function btnHomeButtonEvent( event ) &nbsp;&nbsp;&nbsp; if ("ended" == event.phase ) then &nbsp;&nbsp; &nbsp;RemoveAll() &nbsp;&nbsp; &nbsp;timer.cancel(timerID) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Runtime:removeEventListener( "location", locationHandler ) &nbsp;&nbsp; &nbsp;Runtime:removeEventListener( "key", onKeyEvent ) &nbsp;&nbsp; &nbsp;composer.gotoScene( "scene1" ) &nbsp;&nbsp;&nbsp; end end

Needs to be below the locationHandler function.  Corona SDK is a one pass compiler and at the point you have the code for the removeEventListener() in the function above, locationHandler is likely nil.

Rob

Thanks. Actually I am using the Back button to go back to the home page scene1.

It’s still a matter of code order and when things get values.

Rob