Composer scene:show() - What happens between "will" and "did" ?

I’m using composer in an app and in one of the scenes I read a fairly long list of items (birds actually). Each line is made up from an image an some text. Looks like this:

I have a function called guiClearList() that removes all the GUI elements from the list and one called guiBuildList() that adds them. I use SQLite to read items into an array and what ends up in this array is dependent on how I read from the database (I can do some basic sorting and filtering).

Almost all these operations works quite fast. From the moment I have selected a sort method until the correct list of items is displayed, it takes about half a second.

Filtering also works fast enough. If I select to only show items containing “ibis” in the name, this shows up in a blink.

But the strangest thing is that when I reset the filter (that is: doing a new DB query without any filtering), the result list takes several seconds to show. And it’s not the query that takes time!

My scene:show code looks more or less like this:

function scene:show( event ) local sceneGroup = self.view   local phase = event.phase if ( phase == "will" ) then WaitIcon(true) guiClearList() guiBuildList() -- MARKER A elseif ( phase == "did" ) then -- MARKER b WaitIcon(false) end end

By adding log markers in the code I have found that the part that takes time is between the end of the “will” phase and the start of the “did” phase. The GUI elements are all in place when the waiting-for-nothing starts.

My questions are these:

1. What actually happens between marker A and B?

Since I have no control over what is happening between A & B I’ve been forced to add a wait icon so that the user can see that  something is happening. I’ve tried to use a sprite animation, but it freezes during this time! It is as if the device is locked up completely!

2. What can make the device freeze so utterly so that a sprite animation stops?

3. And, of course, is there a way to get to the bottom of this?

Hi @runewinse,

I think what may be taking awhile is the loading of all these images into memory (I assume there are a lot of them). This is something you don’t have much “direct” control over, but there are methods which could help make the app seem faster, including:

  1. Load the images during the “create scene” phase of Composer, not during “show”. Of course, this will still make it seem slow initially.

  2. Use a native activity indicator instead of a sprite or widget-based activity indicator, while this loading happens:

http://docs.coronalabs.com/api/library/native/setActivityIndicator.html

  1. Instead of loading all of these images at once, load them as they are needed. It looks like you’re populating a tableView() or something along those lines, which should allow you to load the images when they’re about to come on screen.

Hope this helps somewhat,

Brent

The “will” phase fires just before the transition to bring the scene on screen happens.  Then whatever you set the “time” to, that many milliseconds later, the transition should be complete and once it’s fully on screen, the “did” phase fires.  There is no other processing that goes in in between. 

This is designed such that any object creation other than spawning things that have to happen after the screen is loaded and native.* things should happen in the scene:create() function.  If you try to load things in the “will” phase, you’re delaying that load until the time the transition is supposed to happen.

It would seem to me that you should be calling those two function in the scene:create().  If necessary, you can always call the loadScene() API call to pre-execute the scene:create() before you call gotoScene() if you think it takes too long there.

Rob

Ok, thanks to both of you!

My guiClearList() and guiBuildList() look roughly like this:

function guiClearList() for i=#guiArr, 1, -1 do guiArr[i].name:removeSelf() guiArr[i].name = nil guiArr[i].img:removeSelf() guiArr[i].img = nil table.remove(guiArr, i) end end function guiBuildList() print("guiBuildList() - start") for idx = 1, #birdArr do local guiIdx = #guiArr+1 guiArr[guiIdx] = {} guiArr[guiIdx].img = display.newImage() guiArr[guiIdx].name = display.newText() end end

I still don’t get it. I do this in the simplest possible way. Whenever the user changes the sort/filter settings I do this:

A ) Call guiClearList() which completely wipes out all gui elements in the list (:removeSelf() + nil)

B ) Read new set of items from the DB 

C ) Call guiBuildList() which recreates all gui elements

So when the sorting is changed, I don’t just rearrange the gui elements - I do a complete removal and rebuild. Still this operation is quick!

But when I go from a limited data set (filtering) to the complete set, then things takes time. But according the what is really done in guiClearList and guiBuildList I would have thought that a re-sort would take slightly  more  time if anything (more gui elemets to remove before reloading).

The operations are sketched below:

App start load a,b,c,d,e,f,g,h ------------------------------------------------ Sort: remove a,b,c,d,e,f,g,h load   h,g,f,e,d,c,b,a ------------------------------------------------ Filter: remove a,b,c,d,e,f,g,h load   a,b,c Filter off: remove a,b,c load a,b,c,d,e,f,g,h

When the app starts I load all gui elements (unfiltered).

SLOW

Then, if I re-sort, all gui elements are removed and reloaded.

QUICK

Then, if I do a filtering, all gui elements are removed and a limited set is loaded.

Then, if I remove the filter, the limited set of gui elements is removed and a full list of gui elements is reloaded.

SLOW

The only thing I can think of is that the gui elements (images only?) are cached when doing the sort operation, but not  in the filter-on/filter-off operation, but I do not manage to see why one should be cached and not the other.


That said, I must probably stop removing the gui elements then. What should I do instead? Is making them invisible a recommended way?

I suspect there is more to your code than you’re showing.  But I guess my first question is are you using a widget.newTableView() for this?  If not, why not?  It might work better for you.

Rob

There surely is. Anything in particular you’re thinking about?

Oh, the answer to that is simple. Just as with scrollView the (momentum) scrolling of the tableView is not how I want/expect it to be. Far from it, actually. And far from how every other app on my phone handles this aspect of the scrolling.

I’ve written in detail about the woes of the scrollView in this thread: “Is this really how the scrollView is supposed to work?”

It’s a real shame that so much good functionality in Corona SDK is made out of reach, because of this “unfinishedness” of other parts of the SDK.

So, I’ve been forced to code the scrolling behaviour myself and thus cannot make use of all the good stuff in the tableView.


But it would have been great if I could have used tableView. If I have understood correctly, the tableView would automatically have populated the rows on a need-to-show basis, completely eliminating my current problems?

Just for the fun of it, I tried using tableView for my app and even if the scrolling doesn’t work ok, I no longer have this unfortunate delay when removing the filtering as I have with my manual method.

How I wish the widget scrolling would work ok  :slight_smile:

Hi @runewinse,

I think what may be taking awhile is the loading of all these images into memory (I assume there are a lot of them). This is something you don’t have much “direct” control over, but there are methods which could help make the app seem faster, including:

  1. Load the images during the “create scene” phase of Composer, not during “show”. Of course, this will still make it seem slow initially.

  2. Use a native activity indicator instead of a sprite or widget-based activity indicator, while this loading happens:

http://docs.coronalabs.com/api/library/native/setActivityIndicator.html

  1. Instead of loading all of these images at once, load them as they are needed. It looks like you’re populating a tableView() or something along those lines, which should allow you to load the images when they’re about to come on screen.

Hope this helps somewhat,

Brent

The “will” phase fires just before the transition to bring the scene on screen happens.  Then whatever you set the “time” to, that many milliseconds later, the transition should be complete and once it’s fully on screen, the “did” phase fires.  There is no other processing that goes in in between. 

This is designed such that any object creation other than spawning things that have to happen after the screen is loaded and native.* things should happen in the scene:create() function.  If you try to load things in the “will” phase, you’re delaying that load until the time the transition is supposed to happen.

It would seem to me that you should be calling those two function in the scene:create().  If necessary, you can always call the loadScene() API call to pre-execute the scene:create() before you call gotoScene() if you think it takes too long there.

Rob

Ok, thanks to both of you!

My guiClearList() and guiBuildList() look roughly like this:

function guiClearList() for i=#guiArr, 1, -1 do guiArr[i].name:removeSelf() guiArr[i].name = nil guiArr[i].img:removeSelf() guiArr[i].img = nil table.remove(guiArr, i) end end function guiBuildList() print("guiBuildList() - start") for idx = 1, #birdArr do local guiIdx = #guiArr+1 guiArr[guiIdx] = {} guiArr[guiIdx].img = display.newImage() guiArr[guiIdx].name = display.newText() end end

I still don’t get it. I do this in the simplest possible way. Whenever the user changes the sort/filter settings I do this:

A ) Call guiClearList() which completely wipes out all gui elements in the list (:removeSelf() + nil)

B ) Read new set of items from the DB 

C ) Call guiBuildList() which recreates all gui elements

So when the sorting is changed, I don’t just rearrange the gui elements - I do a complete removal and rebuild. Still this operation is quick!

But when I go from a limited data set (filtering) to the complete set, then things takes time. But according the what is really done in guiClearList and guiBuildList I would have thought that a re-sort would take slightly  more  time if anything (more gui elemets to remove before reloading).

The operations are sketched below:

App start load a,b,c,d,e,f,g,h ------------------------------------------------ Sort: remove a,b,c,d,e,f,g,h load   h,g,f,e,d,c,b,a ------------------------------------------------ Filter: remove a,b,c,d,e,f,g,h load   a,b,c Filter off: remove a,b,c load a,b,c,d,e,f,g,h

When the app starts I load all gui elements (unfiltered).

SLOW

Then, if I re-sort, all gui elements are removed and reloaded.

QUICK

Then, if I do a filtering, all gui elements are removed and a limited set is loaded.

Then, if I remove the filter, the limited set of gui elements is removed and a full list of gui elements is reloaded.

SLOW

The only thing I can think of is that the gui elements (images only?) are cached when doing the sort operation, but not  in the filter-on/filter-off operation, but I do not manage to see why one should be cached and not the other.


That said, I must probably stop removing the gui elements then. What should I do instead? Is making them invisible a recommended way?

I suspect there is more to your code than you’re showing.  But I guess my first question is are you using a widget.newTableView() for this?  If not, why not?  It might work better for you.

Rob

There surely is. Anything in particular you’re thinking about?

Oh, the answer to that is simple. Just as with scrollView the (momentum) scrolling of the tableView is not how I want/expect it to be. Far from it, actually. And far from how every other app on my phone handles this aspect of the scrolling.

I’ve written in detail about the woes of the scrollView in this thread: “Is this really how the scrollView is supposed to work?”

It’s a real shame that so much good functionality in Corona SDK is made out of reach, because of this “unfinishedness” of other parts of the SDK.

So, I’ve been forced to code the scrolling behaviour myself and thus cannot make use of all the good stuff in the tableView.


But it would have been great if I could have used tableView. If I have understood correctly, the tableView would automatically have populated the rows on a need-to-show basis, completely eliminating my current problems?

Just for the fun of it, I tried using tableView for my app and even if the scrolling doesn’t work ok, I no longer have this unfortunate delay when removing the filtering as I have with my manual method.

How I wish the widget scrolling would work ok  :slight_smile: