Widget 2.0 Tableview Performance

Thank you guys so freakin much for fixing this!!! I woke up and felt like it was xmas, seeing the tableview all fixed in the daily build. It made my day, now to update my app to this build. Thanks again Danny and Corona Labs!

Any news on when we can look for the updated TableView code?

Yup, this week :slight_smile:

Great! Saw that yesterdays daily contained some tableView tweeks :slight_smile: Thanks for the fix.

Has anyone tested the daily and can provide some info on the performance? How it is now compared to the old tableView? And is it worth migrating the code or are the differences not that big?

It contained more widget fixes than just that also. Seems the daily build summary page is missing information. I’m trying to get the missing information added.

Lazy loading confirmed working again, w00t!

So I put a print in an onRowRender, and sure enough, it’s not calling to render every row at tableView instantiation. In my case, this also means it’s not trying to load hundreds of LARGE image files at once, and now the tableview widget itself is managing which ones to load/unload as the user flicks the screen.

I don’t know how many devs really appreciate all that the lazy loading does for us, but it’s top notch in my book :slight_smile:


Edit: As a side note, the internal workings of the tableView changed somewhat again. Not too difficult to rework the code a little. The hardest part was figuring out how to pass my custom data for row around.

I was proviously just pasting a data item into the row object, but apparently that doesn’t work now - when the onrender gets the row, the pasted on data is gone now (different than prior implementation).

So I saw this cute little field in the row called “id”. Slapped my custom data (image filename) in there, and voila, the onRender picked it up and my images started downloading/inserting again.

Thanks :slight_smile:

I definitely appreciate it - and that the corona devs continue to listen to feedback and/or pestering from the community :slight_smile:

Thank you guys so freakin much for fixing this!!! I woke up and felt like it was xmas, seeing the tableview all fixed in the daily build. It made my day, now to update my app to this build. Thanks again Danny and Corona Labs!

@mpappas, Would it be ok to ask if you could share some code from your project? I’m trying to do similar things and not getting far. Thanks soooo much in advance if you can. 

Apologies for the off-topic request. 

In build 1135 anyways, I set the id on initialization of the row:

[lua]

        – Pre-calc row height in the loop inserting initial rows… then…

        this.messageList:insertRow{
                rowHeight=rowHeight,
                isCategory=isCategory,
                lineColor={96,96,96,255}, – myLineColor,
                rowColor={ default=finalRowColor, over={128,128,128,128} },
                id=tostring(idString),        – remote filename of thumbnail file (full url)
        }
[/lua]

Then later I read it:

[lua]

local function onRowRender( event )
    local row = event.row

    print(" – row.id == ", row.id)

end

[/lua]

Not much to it, my implementation anyways… In my case, I already know the content of the rows when I init the tableview (server responded with the list of data, so I know if there’s an image for each row at list creation time). You could probably stuff a table in the id field, dunno though, never tried.

Thank you so much! So you give the URL of the image to the tableView and it gets displayed how? Do you mean to say you download the images at each run time again & again or do you first download them to your local file system elsewhere? From your comment I think you are downloading them at runtime. 

There’s a lot of my apps code, so I can’t post it all, and trying to snip pieces and post something would be pretty error prone (not to mention take a while), but the overall process in my case is something like:

  • Request chat/blog list from server

  • Receive all the posts/messages

  • Init tableView

  • Create rows (storing any image url in the .id field)

  • onRowRender gets called for the half a dozen or so rows on screen

  • onRowRender checks to see if the filename in the id field (stripped of web url) exists in the system/temp folder

  • if file not exists in cache already, send request to server to download, otherwise, just display it from cache

  • custom listener receives callback when file downloads, calls back a special populateImage listener (Listener keeps table of callers/filenames from event.url returned from server call). File is stored in system/temp folder (cache)

  • populateImage listener a) loads image as picture, and B) rifles through tableview rows until it finds the one with the mathcing url and does an insert() into the _view for that row

Whew! It’s just that simple!

That sounds great! Its much clearer now. Sounds like almost exactly what I need to be doing. I’m simply trying to load some logo images for exhibitors in a festival but the concept is the same. Thanks much for your guidance. 

No problem. It’s more “thinking it through” than actual code (although the code is a little tricky because it’s all so inherently asynchronous - be sure to throw in a few extra print statements).

But on the other hand, you’re probably only 4-5 functions away from having cached web images popping up in your tableViews… And with lazy loading, cached images and smooth as butter scrolling, they’ll be world class tableviews too :slight_smile:

Thanks for the encouragement. I agree! Its amazing what you can do with such little code in Corona SDK once everything is firing off on all cylinders… Those 4-5 functions are going to take me some time to crack but I’ll keep trying.

Aww what the heck, these two are mostly complete, and pretty generic. Ones calls back, the other either returns the file pronto, or delays the callback until when the file does arrive…  If you can figure out how to use them, then your halfway done :slight_smile:

[lua]

local pendingDownloads = {}     – Files we’ve called to download, but haven’t arrived yet.
 

local function downloadComplete(event)          – Calls back original source, clears the pending flag…

    if( event.url ~= nil ) then
        pendingDownloadsevent.url      – Call the completion listener…     
        pendingDownloads[event.url] = nil       – And remove the pending flag…
    end

    return true
end
 –
 – download file takes a full url as arg, and checks actual filename at end to see if it is in cache already. If not, sends the request.
 – NOTE: uses system tempDirectory for storiing/caching files… When complete, calls back completionListener.
 –
 function downloadFile(fileLocation, completionListener)
    
–    print(" – downloadFile() – fileLocation == “, fileLocation)
 
    – Let’s get the base filename, without path…
    local fileName = getBaseFilename(fileLocation)
–    print( " — Found the base fileName, string is: " … fileName )    
 
     – Now  determine if the file is already cached…
     if( cacheFileExists(fileName) ) then
        local tempEvent = {}
        tempEvent.response = fileLocation
        tempEvent.phase = “ended”
        tempEvent.url = fileLocation
–        print(” **** Found the cache file, calling back ***")
        completionListener(tempEvent)       – Simulate OS callback event struct…    
     else     
        if( pendingDownloads[fileLocation] ~= nil ) then    – We’re still waiting for it??
–            print("  **** DOWNLOAD STILL PENDING FOR: “, fileLocation)
            return        
        else    – else not pending or chaced, start the downoload…
            pendingDownloads[fileLocation] = completionListener       
            network.download( fileLocation, “GET”, downloadComplete, fileName ,system.TemporaryDirectory )   
–            print(”  ************************ Downloading actual file ==", fileLocation)            
        end
    end
 
 end

[/lua]

and a couple of the little support functions:

[lua]

– cacheFileExists() – returns true if file exists in app Temp folder, false if not… Done this way because some web servers return large 404 files which count as files… so filesize must be greater than 512 to count/be able to tell…
function cacheFileExists(theFile)

    local retVal = false    – By default, file doesn’t exist
    local path = system.pathForFile( theFile, system.TemporaryDirectory )
    
    if( path ) then                              
–        print("***** Path for File ==", path)
        local fh, errStr = io.open( path, “r” )  
        if( fh ) then   
            local fileLength = fh:seek(“end”)
–            print(" – cache file fileLength == ", fileLength )
            if( fileLength > 512 ) then         – Our server returns an html file with message 404 error that is about 400 bytes long if graphic file requested is NOT there… so check for length of file server returned… Your mileage may vary.
                retVal = true                   – Tell the caller that the file DOES exist…
            end
            io.close(fh)        – close the file…
        end
    end
    
    return retVal
end
 

function getBaseFilename(fileLocation)      – Gets the base filename from a long path string ( the stuff after the last slash \ )

    – Let’s get the base filename, without path…
    local startChar=1
    local endChar=1
    local fileName = fileLocation
    
    – String find is giving me a hard time searching from the end, so we will whittle it down from the beginning…
    – I really should read up and practice with the string library :confused:

    – This entire function could probably be replaced with 1 line of code.  
    while ( startChar ~= nil ) do
        startChar, endChar = string.find(fileName, “/”)
    
–        print(" – found char at position: “, startChar)
        if( startChar ~= nil ) then
            fileName = string.sub(fileName, startChar+1, -1)  – Get the sub to the end of the string
–            print(” - fileName = ", fileName)    
        end
    end
    
    return fileName
end
 

[/lua]

You sir are an angel. Thank you very much!!!

oh snap ksan, I just made a workaround for my row.reRender problem… Since they changed the tableViews, they got rid of that ‘feature’… But after posting this and remembering how it works, I realized my pics are updating onscreen fine, without a reRender function / feature…

Turns out it’s because they are inserted, not just a text field changed… So I did some messing around, and got a text string to rerender on the fly in my tableviews now too… 

I am doing it by keeping a pointer to the rows text object in my other structure, the one I get back from server… When a minute passes (it’s a “minutes ago” counter), my routine scans through the rows, does a _view._rows[i]._view:remove(currentMessages[i].TS) (the last bit is my saved off pointer from when it was created for that row), regenerate the string and then insert into the same place… And it updates onscreen instantly now…

So, I got something out of it too, a way around the dreaded reRender issue for now :slight_smile:

My life is a series of "Oh snap!"s these days so whats yet another one…  :slight_smile:

I’m slowly working my way towards your code. My first step was to get the file name pointer which I now have. Next step is to go through the download process… Wish me luck! 

Thanks much for your help once again.