Native.showAlert() Problem in Storyboard

I’m having a weird problem with native.showAlert(), that began when I upgraded to SDK 2013.2076
 
After re-optimizing my app, changing everything that was deprecated (Migration Guide 2.0), etc. this seems to be the only thing bogging me down.
 
What’s happening is here is, I have an alert that I want to show up when the scene is done loading – enterScene. I place the alert there, and when I run the app, (going through the previous 6 scenes before this 7th current scene) the alert pops up just fine. Except I keep getting this WARNING message:
 

2013-11-24 18:11:37.273 Corona Simulator[945:507] WARNING: The simulator does not support simultaneous alerts via native.showAlert(). If an alert is shown, subsequent calls will be ignored.

2013-11-24 18:11:37.274 Corona Simulator[945:507] WARNING: The simulator does not support simultaneous alerts via native.showAlert(). If an alert is shown, subsequent calls will be ignored.

2013-11-24 18:11:37.274 Corona Simulator[945:507] WARNING: The simulator does not support simultaneous alerts via native.showAlert(). If an alert is shown, subsequent calls will be ignored.

2013-11-24 18:11:37.274 Corona Simulator[945:507] WARNING: The simulator does not support simultaneous alerts via native.showAlert(). If an alert is shown, subsequent calls will be ignored.

2013-11-24 18:11:38.424 Corona Simulator[945:507] WARNING: The simulator does not support simultaneous alerts via native.showAlert(). If an alert is shown, subsequent calls will be ignored.

Yes, that is the full terminal output that results from just one alert, that it apparently doesn’t like! lol.

So, I spent hours, two full days working at such an peculiar problem. I made a small sample project isolating the problem. All of my code between the original project, and the problem testing project is exactly the same, minus some extraneous, cinematic detail that wouldn’t effect the problem, it basically just cuts to the chase. All variables are set the same way, and same goes for calling all functions that were called during said scenes.

What I came to find out was that whether I put the alert inside of the createScene() portion, or enterScene portion of storyboard, that weird warning (those warnings, I should add) did not occur. This applies to the problem tester app. For some reason, and I feel like it could my doing, or the upgrade, since this problem never happened with my prior build, 2013.1202. The funny thing about this is that I have other alerts during my game. So I wanted to see if this msg only happens with the “first alert” that the app encounters, ignoring the rest. I commented the problem alert out, and let the app run until the next alert, which gave no warning/problematic output. So it has something to do with this current scene, I believe.

“Why does he care if the app still works, its just a warning.” you might add.

What happens is, when I build the app, and put it to my Android phone, when it gets to the said scene, it displays 5 alerts, stacked upon each other. So it takes 5 clicks or taps, of the ‘ok’ button until I get to fully see and interact with the display objects, that were created in createScene().

After a full day of endless research and failed attempts, I finally got the problem fixed. I simply moved my alert as the last “item” or code, if you will, under the createScene() field. This produced no warning messages. Why would Corona give me a warning, only because I wanted an alert to occur during enterScene()??? 

The funny thing is, that other alert I talked about earlier that is in a few scenes later in my game, guess what. It is in the enterScene() field, and produces no warning message. That is why I believe there is something wrong with this one scene.

Has anyone had any problems like this? [I really think its me, but I can’t see any mistakes!]

Am I doing something wrong with alerts?

Thanks, I really hope you can help.

Isiah.

I’ve seen something like this and its usually because the scene is being called multiple times.  This could happen from trying to go to a scene in the middle of a touch-drag move phase.  It could happen from a touch handler where you’re not checking the phase of the event (and you get a began phase, ended phase and possible move phases) and each one calls storyboard.gotoScene().

Without seeing your code its going to be hard to identify what is going on.

Rob

Here is the problematic code. @Rob

---------------------------------------------------------------------------------- -- -- scenetemplate.lua -- ---------------------------------------------------------------------------------- local storyboard = require( "storyboard" ) local widget = require( "widget" ) local scene = storyboard.newScene() local nextbtn local hello = 0 ---------------------------------------------------------------------------------- -- -- NOTE: -- -- Code outside of listener functions (below) will only be executed once, -- unless storyboard.removeScene() is called. -- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- -- BEGINNING OF YOUR IMPLEMENTATION --------------------------------------------------------------------------------- -- Called when the scene's view does not exist: function scene:createScene( event ) local group = self.view local bg = display.newImageRect("CLUE/Texture/silver.jpg" , \_W, \_H) setAnchor(bg,"TopLeft") setPos(bg,"TopLeft") group:insert(bg) local swipebtn = display.newImage("CLUE/prompts/swipe.png") setAnchor(swipebtn,"Center") swipebtn.x = \_W/2 swipebtn.y = 120 scale(swipebtn,1.5) group:insert(swipebtn) nextbtn = display.newImage("CLUE/prompts/next.png")--to be accessed in ENTERSCENE function setAnchor(nextbtn,"Center") nextbtn.x = \_W/2 -- .25\*\_W nextbtn.y = 1185 scale(nextbtn,1.5) group:insert(nextbtn) --3181.9+180 dealCards() local scrollView = widget.newScrollView { width = 720, height = 480\*1.7, left = 0,--x top = 0,--y scrollWidth = 0, scrollHeight = 0, hideBackground = true, hideScrollBar = true, maskFile = "blackbitmap.png", verticalScrollDisabled = true, rightPadding = 180 } --scrollview object sits at the top of the screen, x = 0, y = 0 setPos(scrollView,"Center") group:insert(scrollView)--dont have to worry about cleaning this up --function that assigns correct picture to correct card number --only showing the user's (whichever player that is) cards to himself on the screen! for i = 1, 5 do players[1].cards[i].pic = keySWP(players[1].cards[i].cardNum) --card dimension is 323 x 480 setAnchor(players[1].cards[i].pic,"Center") scale(players[1].cards[i].pic, 1.7) players[1].cards[i].pic.x = (i\*660 - 660) + (\_W/2) players[1].cards[i].pic.y = .5\*(480\*1.7) --center of card in middle of scrollview, initially it was at the top of scrollView scrollView:insert(players[1].cards[i].pic) print("User has card #"..players[1].cards[i].cardNum) --should also print all the other comp's cards to ensure shuffle works end --next make a "swipe left to reveal your cards" prompt and add a next button. --next scene should be to display turn one, player, and then based on whether --its a comp or user turn, start that turn! start the main loop... --make "swipe to reveal your deck" prompt and "next" button. for a = 1, 6 do for b = 1, 5 do --print(players[a].role.." is "..players[a].name.." and has card #"..players[a].cards[b].cardNum) end end local go = function(e) storyboard.gotoScene( "scene8",{time = 1000, effect = "fade"} ) end timer.performWithDelay( 1000, go ) end -- Called immediately after scene has moved onscreen: function scene:enterScene( event ) local group = self.view local onComplete = function ( event )--after saying OK to the alert if "clicked" == event.action then local i = event.index if 1 == i then local animate = function(obj, max, min) if obj.xScale \>= max then dir = 'down' elseif obj.xScale \<= min then dir = 'up' end if dir == 'down' then scale(obj,obj.xScale - .030) elseif dir == 'up' then scale(obj,obj.xScale + .030) end end listenerA = function(event)--enterFrame event animate(nextbtn, 1.9, 1.5) end Runtime:addEventListener( "enterFrame", listenerA )--scope = IF STATEMENT local goToNextScene = function (event)--listener, occurs once event takes place Runtime:removeEventListener("enterFrame", listenerA) transition.to( nextbtn, {time = 200, xScale = 1.5, yScale = 1.5, alpha = 1} ) print( "listener called" ) local options = { effect = "fade", time = 1200 } --storyboard.gotoScene( "scene8" , options) storyboard.gotoScene( "scene3" , options) end nextbtn:addEventListener("tap" , goToNextScene)--event, a tap on the button --any listeners attached to D.O.s in scene group will be auto taken care of. end end end alert1 = native.showAlert( "Clue", "This is your hand.", { "OK."}, onComplete ) end -- Called when scene is about to move offscreen: function scene:exitScene( event ) local group = self.view ----------------------------------------------------------------------------- -- INSERT code here (e.g. stop timers, remove listeners, unload sounds, etc.) ----------------------------------------------------------------------------- end -- Called prior to the removal of scene's "view" (display group) function scene:destroyScene( event ) local group = self.view ----------------------------------------------------------------------------- -- INSERT code here (e.g. remove listeners, widgets, save state, etc.) ----------------------------------------------------------------------------- --Runtime:removeEventListener("enterFrame", listenerA) native.cancelAlert( alert1 ) alert1 = nil dealCards = nil goToNextScene = nil onComplete = nil end --------------------------------------------------------------------------------- -- END OF YOUR IMPLEMENTATION --------------------------------------------------------------------------------- -- "createScene" event is dispatched if scene's view does not exist scene:addEventListener( "createScene", scene ) -- "enterScene" event is dispatched whenever scene transition has finished scene:addEventListener( "enterScene", scene ) -- "exitScene" event is dispatched before next scene's transition begins scene:addEventListener( "exitScene", scene ) -- "destroyScene" event is dispatched before view is unloaded, which can be -- automatically unloaded in low memory situations, or explicitly via a call to -- storyboard.purgeScene() or storyboard.removeScene(). scene:addEventListener( "destroyScene", scene ) --------------------------------------------------------------------------------- return scene

See anything wrong?

Also, the scene prior, to this has a timer.performWithDelay() that calls the listener, which…AHHHHHHH!!! I THINK I FOUND SOMETHING YOUR A GENIUS!!! *bows in your presence* hold up let me try something and see if it works. :DDDDD

The code in this scene is not likely the problem.  Hope you find it!

Rob

*ignore this msg*

@Rob 

Ok what was happening was as I was cleaning up code as I learned new things. I decided to put these.

transition.to(object[1], {time = a, delay = b, x = x, y = y, transition = easing.inExpo, onComplete = goToNextScene} ) transition.to(object[2], {time = a, delay = b, x = x, y = y, transition = easing.inExpo, onComplete = goToNextScene} ) transition.to(object[3], {time = a, delay = b, x = x, y = y, transition = easing.inExpo, onComplete = goToNextScene} ) transition.to(object[4], {time = a, delay = b, x = x, y = y, transition = easing.inExpo, onComplete = goToNextScene} ) transition.to(object[5], {time = a, delay = b, x = x, y = y, transition = easing.inExpo, onComplete = goToNextScene} ) transition.to(object[6], {time = a, delay = b, x = x, y = y, transition = easing.inExpo, onComplete = goToNextScene} )

into a for loop like such:

for i = 1, 6, 1 do transition.to(object[i], {time = a, delay = b, x = x, y = y, transition = easing.inExpo, onComplete = goToNextScene} ) end

so the following scene was being called 5 more times than it should have been, which is why the warning popped up 5 times, and consequently, the alert on the phone as well.

I made a quick, but paramount change that makes all the difference right here!

for i = 1, 6, 1 do if i == 6 then transition.to(object[i], {time = a, delay = b, x = x, y = y, transition = easing.inExpo, onComplete = goToNextScene} ) else transition.to(object[i], {time = a, delay = b, x = x, y = y, transition = easing.inExpo} ) end

this way, the onComplete only registers one time! I knew there was something this small that was messing it up! Thank you so much!

But this is a valuable lesson when it comes to onComplete listeners and for loops. 

Thanks Rob!

Isiah.

I’ve seen something like this and its usually because the scene is being called multiple times.  This could happen from trying to go to a scene in the middle of a touch-drag move phase.  It could happen from a touch handler where you’re not checking the phase of the event (and you get a began phase, ended phase and possible move phases) and each one calls storyboard.gotoScene().

Without seeing your code its going to be hard to identify what is going on.

Rob

Here is the problematic code. @Rob

---------------------------------------------------------------------------------- -- -- scenetemplate.lua -- ---------------------------------------------------------------------------------- local storyboard = require( "storyboard" ) local widget = require( "widget" ) local scene = storyboard.newScene() local nextbtn local hello = 0 ---------------------------------------------------------------------------------- -- -- NOTE: -- -- Code outside of listener functions (below) will only be executed once, -- unless storyboard.removeScene() is called. -- --------------------------------------------------------------------------------- --------------------------------------------------------------------------------- -- BEGINNING OF YOUR IMPLEMENTATION --------------------------------------------------------------------------------- -- Called when the scene's view does not exist: function scene:createScene( event ) local group = self.view local bg = display.newImageRect("CLUE/Texture/silver.jpg" , \_W, \_H) setAnchor(bg,"TopLeft") setPos(bg,"TopLeft") group:insert(bg) local swipebtn = display.newImage("CLUE/prompts/swipe.png") setAnchor(swipebtn,"Center") swipebtn.x = \_W/2 swipebtn.y = 120 scale(swipebtn,1.5) group:insert(swipebtn) nextbtn = display.newImage("CLUE/prompts/next.png")--to be accessed in ENTERSCENE function setAnchor(nextbtn,"Center") nextbtn.x = \_W/2 -- .25\*\_W nextbtn.y = 1185 scale(nextbtn,1.5) group:insert(nextbtn) --3181.9+180 dealCards() local scrollView = widget.newScrollView { width = 720, height = 480\*1.7, left = 0,--x top = 0,--y scrollWidth = 0, scrollHeight = 0, hideBackground = true, hideScrollBar = true, maskFile = "blackbitmap.png", verticalScrollDisabled = true, rightPadding = 180 } --scrollview object sits at the top of the screen, x = 0, y = 0 setPos(scrollView,"Center") group:insert(scrollView)--dont have to worry about cleaning this up --function that assigns correct picture to correct card number --only showing the user's (whichever player that is) cards to himself on the screen! for i = 1, 5 do players[1].cards[i].pic = keySWP(players[1].cards[i].cardNum) --card dimension is 323 x 480 setAnchor(players[1].cards[i].pic,"Center") scale(players[1].cards[i].pic, 1.7) players[1].cards[i].pic.x = (i\*660 - 660) + (\_W/2) players[1].cards[i].pic.y = .5\*(480\*1.7) --center of card in middle of scrollview, initially it was at the top of scrollView scrollView:insert(players[1].cards[i].pic) print("User has card #"..players[1].cards[i].cardNum) --should also print all the other comp's cards to ensure shuffle works end --next make a "swipe left to reveal your cards" prompt and add a next button. --next scene should be to display turn one, player, and then based on whether --its a comp or user turn, start that turn! start the main loop... --make "swipe to reveal your deck" prompt and "next" button. for a = 1, 6 do for b = 1, 5 do --print(players[a].role.." is "..players[a].name.." and has card #"..players[a].cards[b].cardNum) end end local go = function(e) storyboard.gotoScene( "scene8",{time = 1000, effect = "fade"} ) end timer.performWithDelay( 1000, go ) end -- Called immediately after scene has moved onscreen: function scene:enterScene( event ) local group = self.view local onComplete = function ( event )--after saying OK to the alert if "clicked" == event.action then local i = event.index if 1 == i then local animate = function(obj, max, min) if obj.xScale \>= max then dir = 'down' elseif obj.xScale \<= min then dir = 'up' end if dir == 'down' then scale(obj,obj.xScale - .030) elseif dir == 'up' then scale(obj,obj.xScale + .030) end end listenerA = function(event)--enterFrame event animate(nextbtn, 1.9, 1.5) end Runtime:addEventListener( "enterFrame", listenerA )--scope = IF STATEMENT local goToNextScene = function (event)--listener, occurs once event takes place Runtime:removeEventListener("enterFrame", listenerA) transition.to( nextbtn, {time = 200, xScale = 1.5, yScale = 1.5, alpha = 1} ) print( "listener called" ) local options = { effect = "fade", time = 1200 } --storyboard.gotoScene( "scene8" , options) storyboard.gotoScene( "scene3" , options) end nextbtn:addEventListener("tap" , goToNextScene)--event, a tap on the button --any listeners attached to D.O.s in scene group will be auto taken care of. end end end alert1 = native.showAlert( "Clue", "This is your hand.", { "OK."}, onComplete ) end -- Called when scene is about to move offscreen: function scene:exitScene( event ) local group = self.view ----------------------------------------------------------------------------- -- INSERT code here (e.g. stop timers, remove listeners, unload sounds, etc.) ----------------------------------------------------------------------------- end -- Called prior to the removal of scene's "view" (display group) function scene:destroyScene( event ) local group = self.view ----------------------------------------------------------------------------- -- INSERT code here (e.g. remove listeners, widgets, save state, etc.) ----------------------------------------------------------------------------- --Runtime:removeEventListener("enterFrame", listenerA) native.cancelAlert( alert1 ) alert1 = nil dealCards = nil goToNextScene = nil onComplete = nil end --------------------------------------------------------------------------------- -- END OF YOUR IMPLEMENTATION --------------------------------------------------------------------------------- -- "createScene" event is dispatched if scene's view does not exist scene:addEventListener( "createScene", scene ) -- "enterScene" event is dispatched whenever scene transition has finished scene:addEventListener( "enterScene", scene ) -- "exitScene" event is dispatched before next scene's transition begins scene:addEventListener( "exitScene", scene ) -- "destroyScene" event is dispatched before view is unloaded, which can be -- automatically unloaded in low memory situations, or explicitly via a call to -- storyboard.purgeScene() or storyboard.removeScene(). scene:addEventListener( "destroyScene", scene ) --------------------------------------------------------------------------------- return scene

See anything wrong?

Also, the scene prior, to this has a timer.performWithDelay() that calls the listener, which…AHHHHHHH!!! I THINK I FOUND SOMETHING YOUR A GENIUS!!! *bows in your presence* hold up let me try something and see if it works. :DDDDD

The code in this scene is not likely the problem.  Hope you find it!

Rob

*ignore this msg*

@Rob 

Ok what was happening was as I was cleaning up code as I learned new things. I decided to put these.

transition.to(object[1], {time = a, delay = b, x = x, y = y, transition = easing.inExpo, onComplete = goToNextScene} ) transition.to(object[2], {time = a, delay = b, x = x, y = y, transition = easing.inExpo, onComplete = goToNextScene} ) transition.to(object[3], {time = a, delay = b, x = x, y = y, transition = easing.inExpo, onComplete = goToNextScene} ) transition.to(object[4], {time = a, delay = b, x = x, y = y, transition = easing.inExpo, onComplete = goToNextScene} ) transition.to(object[5], {time = a, delay = b, x = x, y = y, transition = easing.inExpo, onComplete = goToNextScene} ) transition.to(object[6], {time = a, delay = b, x = x, y = y, transition = easing.inExpo, onComplete = goToNextScene} )

into a for loop like such:

for i = 1, 6, 1 do transition.to(object[i], {time = a, delay = b, x = x, y = y, transition = easing.inExpo, onComplete = goToNextScene} ) end

so the following scene was being called 5 more times than it should have been, which is why the warning popped up 5 times, and consequently, the alert on the phone as well.

I made a quick, but paramount change that makes all the difference right here!

for i = 1, 6, 1 do if i == 6 then transition.to(object[i], {time = a, delay = b, x = x, y = y, transition = easing.inExpo, onComplete = goToNextScene} ) else transition.to(object[i], {time = a, delay = b, x = x, y = y, transition = easing.inExpo} ) end

this way, the onComplete only registers one time! I knew there was something this small that was messing it up! Thank you so much!

But this is a valuable lesson when it comes to onComplete listeners and for loops. 

Thanks Rob!

Isiah.