Event Driven learning for an old and slow Procedural programmer ...

Yes, a listener it’s called usually in corona. I usually call then “callbacks” because my code gets called back when something happens… (Like in the network.request(), your specified code gets called back when the request completes / fails).

For the listeners, you usually have to install the listener first, then remove the listener later, as in:

        Runtime:addEventListener( “enterFrame”, screenUpdate )

and

        Runtime:removeEventListener( “enterFrame”, screenUpdate )                  
 

as opposed to the one shot deal like the network.request() “listener” (or callback, as I usually say for that one).

But they both kinda cause the same thing to happen – a function of yours gets called when something in particular happens.

Thank you all for your contributions. This is getting better. Not 2nd nature yet but hanging in there. 

Ok. I’m back. Here’s why I am still on shaky ground… I was trying to understand the native.setActivityIndicator() and was thrown off by a comment by Brent in a spinner thread… He said 

Just remember that you can’t start and stop the indicatorin the same code chunk… you need to start it when the process begins, and then queue a callback or other function to stop it when the process is complete.

This was a moment of clarity, I thought I understood it but I still wanted to challenge it. Challenge was to simplify the ActivityIndicator sample to its barebones and then write it in a non-event driven , sequential manner. I was hoping to understand this more and along the way I managed to confuse myself some more… 

Here is barebones Activity Indicator code. This will just put up the background image and then count to 5 while showing the ActivityIndicator and then take it away.

local numSeconds = 5 local counter = display.newText( tostring( numSeconds ), 0, 0, system.systemFontBold, 36 ) function counter:timer( event ) numSeconds = numSeconds - 1 counter.text = tostring( numSeconds ) if 0 == numSeconds then native.setActivityIndicator( false ); end end timer.performWithDelay( 1000, counter, numSeconds ) native.setActivityIndicator( true ); display.newImage( "aquariumbackgroundIPhone.jpg", 0, 0 )

Then I wrote the following. I put in specific print lines in between to prove sequential execution… 

print ("line 1", os.time() ) local numSeconds = 5 print ("line 2", os.time() ) display.newImage( "aquariumbackgroundIPhone.jpg", 0, 0 ) print ("line 3", os.time() ) native.setActivityIndicator( true ); print ("line 4", os.time() ) local counter = display.newText( tostring( numSeconds ), 0, 0, system.systemFontBold, 36 ) print ("line 5", os.time() ) local markTime = os.time() print ("line 6", os.time() ) local timePassed = os.time() - markTime print ("line 7", os.time() ) while timePassed \< 5 do timePassed = os.time() - markTime counter = display.newText( tostring( timePassed ), 0, 0, system.systemFontBold, 36 ) end print ("line 8", os.time() ) native.setActivityIndicator( false ); print ("line 9", os.time() )

So there I was trying to prove it can be done. I was wrong. The background image did not come through all the way until the end of the countdown of 5 seconds. The call to put it up is right at the top of this code. I see 

print (“line 2”, os.time() )
print (“line 3”, os.time() )

In the terminal but the call to display the background image which is right in between them does not execute sequentially. This is driving me mad. I can’t understand it. I know this is the way its meant to be and this is completely normal in this new event driven world but I can’t wrap my head around it. 

Why can’t I make this work sequentially? Thank you very much for your patience with me.

I am still trying to understand why the background image does not pop up before the native.activityindicator() in my sequential code. I think this is because display.newImage is called on the 2nd line and this starts a thread to make this happen. The code control returns to my code and the 3rd line and onwards gets executed while the processor is trying to make my display.newImage thread happen. Because it takes considerably longer (in CPU cycles) to load and display a full screen image the code flies through the next bunch of lines and so native.activityindicator() takes over blanking the screen. Am I on the right track to understanding this thing?

The irony is how in the event driven example display.newImage is the last line in the code and yet it executes as needed. In my sequential code it is right at the top and doesn’t get the focus… I know I’m about to crack this mental block. Almost there.

Final question… If you really really really must put some processes in order how do you go about making sure one will wait for the other? Example

Open DB,

if not exist create DB

download data from web into DB

Load Scene

Load widgets in the create scene

Load data into widgets create scene

In my app it takes too long to process the create db and populate it from the web so the app flies through the scene, widgets, load data part. Since the data is not there yet it sits there showing an empty tableview. My current fix is to call a reload of the scene once my data download process is done. I work around it but I still feel its not the most elegant way to do this… 

Am I splitting hair on this? It works so I am happy. Just want to understand. Sorry for being so stubborn.

It’s because your code doesn’t do the actual updates, the OS does… It has no chance to update the screen during your 5 second loop there… I have broken your code up so that the OS is back in charge, and it basically does the same thing… Just, in an “OS is in charge of the display” sort of fashion…

[lua]

– A little example of the event driven screen updates (done by the OS, not by the app…)

local counter = nil
local markTime = os.time()
 
local function showBG()
    print(" – ShowBG()")
    display.newImage( “Bg02.png”, 0, 0 )
    
    – Lets initialize the onscreen counter
    counter = display.newText( “Counter”, 100, 100, system.systemFontBold, 36 )
    
end

local function doCount()
    print(" – doCount()")

local timePassed = os.time() - markTime

    if( counter ~= nil ) then
        counter:removeSelf()
        counter = nil
    end

    if( timePassed < 5 ) then
        counter = display.newText( tostring( timePassed ), 100, 100, system.systemFontBold, 36 )
        timer.performWithDelay( 1000, function()  doCount() end, 1) – do it again in another second from now
   else
        counter = display.newText( tostring( “Done.” ), 100, 100, system.systemFontBold, 36 )   
        native.setActivityIndicator( false );
   end

    – Exit, and the OS can update the screen…
end


– This is your “main” code, it executes immiediately…

print (“line 1”, os.time() )
showBG()        – executes right away… but screen doesn’t update until “next frame” after this main code completes…

print (“line 2”, os.time() )
native.setActivityIndicator( true ) – will not happen onscreen until after all this code completes…
       
print (“line 3”, os.time() )
timer.performWithDelay( 1000, function()  doCount() end, 1) – After one second, update the onscreen timer…

print (“line 4”, os.time() )

[\lua]

@ mpappas, thanks much for taking the time to help me. it is getting much clearer. Lets take your edition of the sample one more step closer to my real world challenge. 

timer.performWithDelay( 1000, function()  doCount() end, 1)

keeps calling back (is that the right term, callback?) doCount which does the job of updating the screen count and eventually calling off the ActivityIndicator.

In my case I could have the dbUpdate function replace doCount() and have a similar timer.performWithDelay keep throwing focus back at it. the dbUpdate could keep track of a variable to know if its done its job or not and if it has then it can call off the ActivityIndicator.

Is this how you would do it in the event driven world? For my aging single line sequential mind it appears to be a waste of CPU ticks to do the timer thing but if this is how its done then so be it… 

I think I’m getting somewhere!  :) 

Thank you very much!!!

It’s one way how onscreen timers / updates happen… But as far as loading / working with a db, there’s differences in how those async / event driven systems work too…

But overall, yes – You could keep a “state” variable for the current state of your app/db, and display the current state onscreen in a display update routine (reading global vars on a timer, something like as above)…

But if you are using a server, and waiting for data from it, you’ll have to do the event driven / async thing at the same time.

The idea is, you send off a request for data with something like the network.request() call, and in the call you include a callback pointer. Just before you called the server, you would change your “state” variable to the “waitingServerReply” state (and your screen display routines would pick it up and display that).

When the callback happens (the server has replied), you would update the state to the next state, and your display routines would go from there (populating tableViews with the processed data or whatever)…

(Not sure if I’m making much sense here…)

Yup. Making much sense. Thanks much. When you say “you include a callback pointer” you are actually referring to setting up a listener right? I need to read up on this a little more. Yeayy for weekend. Thanks much and wishing you all a great weekend.

EDIT. This definitely helped me. I completely managed to get my activityindicator under control during a complicated startup routine. Still lots of ways to go before I can say I am thinking event driven as opposed to sequential. Huge paradigm shift but slowly getting there…

Yes, a listener it’s called usually in corona. I usually call then “callbacks” because my code gets called back when something happens… (Like in the network.request(), your specified code gets called back when the request completes / fails).

For the listeners, you usually have to install the listener first, then remove the listener later, as in:

        Runtime:addEventListener( “enterFrame”, screenUpdate )

and

        Runtime:removeEventListener( “enterFrame”, screenUpdate )                  
 

as opposed to the one shot deal like the network.request() “listener” (or callback, as I usually say for that one).

But they both kinda cause the same thing to happen – a function of yours gets called when something in particular happens.