Table and display.loadRemoteImage

Hi,

I’m building an app which loads product list(product name, image ) json file from a remote location.

The images are loading using  display.loadRemoteImage and insert into to the row. I noticed when I scroll table view up and down some times images get stuck in the top - see attachment. is this a known issue ? Any work around?

I don’t why corona built app table view is slow. The page doesn’t scroll smoothly as opposed to built with objective c. I’m using some sample code from business app. should I use html and webview ? Corona doesn’t handle native - text field or web view properly.

Do you know any app which uses images in the table view as list? I just want to see the performance and how smooth it is?

Thanks in advance.

Regards

Hi David,

I’m not sure why images are getting “stuck” (it may be some aspect of your code), but generally speaking, you’re not going to achieve smooth tableView scrolling with remotely-loaded images unless you preload them first. If the tableView constantly needs to “request” an image via network each time it’s about to come into view, it will lag, especially if the user scrolls very fast. If possible, you need to figure out a way to pre-load all of the images, or (if this is impossible for some design reason), pre-load a certain number of them which you’ll know are going to come into view, then load another chunk behind the scenes, and so forth.

Hope this helps somewhat,

Brent

Thank you for the reply. I will try - display 10 items and pre load images then add lazy loading …

I’ve seen lots of iphone app which has tons of images in a table and it loads smoothly… all images has preloader and they look professional. Is this a Corona limitation.

Here is code -

function displayData(id) myList=json.decode(loadValue(id..'.txt')); for key,value in pairs(myList.data) do --local isCategory = false local rowHeight = 250 -- local rowColor = { tableView:insertRow { rowHeight = rowHeight, isCategory = false, rowColor = { 1, 1, 1 }, lineColor = { 0.90, 0.90, 0.90 }, params = { title = myList.data[key].title, price = myList.data[key].price, price2 = myList.data[key].price2, desc = myList.data[key].sdesc, img = myList.data[key].img, imgfile = myList.data[key].imgfile, thumb = myList.data[key].thumb } } end end local function onRowRender( event ) local phase = event.phase local row = event.row local params = event.row.params local filename = params.imgfile local function thumbListener( event ) if ( event.isError ) then else event.target.alpha = 0 -- -- This is scaling code. I have no idea how big the downloaded image was. -- Divide the desired height of the image by the real height and that gives us a number we -- can feed to the scale() method to keep the image's aspect ratio and controlling the height. -- If you need to furhter control the width, you could do a second pass kind of like this: -- -- if w \* s \> maxWidth then s = maxWidth / w end -- -- and feed the new s value to the scale() method. -- local w = event.target.width --print(w..display.contentWidth) local h = event.target.height local s = 100 / h local offset=0 if w \> display.contentWidth then local diff = w-display.contentWidth; offset = math.abs(display.contentWidth-diff/2); print(w..display.contentWidth..offset) else offset = display.contentWidth-w end event.target:scale(s,s) event.target.anchorX = 0 event.target.anchorY = 0 event.target.x =0 event.target.y = 0 -- -- put the image into the row -- row:insert(event.target) event.target.alpha=1 --transition.to( event.target, {time=100, alpha = 1.0 } ) end end -- downloadFile(params.thumb,completionListener) local groupContentHeight = row.contentHeight if params.img then display.loadRemoteImage(params.img, "GET", thumbListener, filename, system.CachesDirectory, 0, 0 ) end if params.price then local rowPrice = display.newText( row, params.price, 0, 0,240, 0, myApp.font,18) rowPrice.x = display.contentWidth-60 rowPrice.anchorX = 0 rowPrice.y =groupContentHeight \* 0.85 rowPrice:setFillColor(0,0,0) if params.price2 then local rowPrice2 = display.newText( row, params.price2, 0, 0,240, 0, myApp.font,14) rowPrice2.x = display.contentWidth-60 rowPrice2.anchorX = 0 rowPrice2.y =groupContentHeight \* 0.91 rowPrice2:setFillColor(0,0,0) end local rowTitle = display.newText( row, params.title, 0, 0,240, 0, myApp.font,15) rowTitle.x = 10 rowTitle.anchorX = 0 rowTitle.y =groupContentHeight \* 0.9 rowTitle:setFillColor(0,0,0) end end

The problem is rows are destroyed when they are out of view.  When the row is in view it calls the the render function, which initiates the load remote image.  When the row is out of focus it gets destroyed. The load remote image handler is trying to add it to a group that no longer exists, so it get pushed into the default group.

In my app I did some debugging and noticed there are properties I could check to see if the row was not destroyed yet.  I picked the _proxy.

see http://forums.coronalabs.com/topic/44839-newtableview-asynchronous-lazy-loading-with-loadremoteimage/#entry233771

You don’t want the image downloaded each time the row comes in/out of focus, so you’ll want to save it in the temp dir and check if the file exists first before downloading.

I have some code that does all this somewhere, but I haven’t touch corona for 4 months.  Maybe something has been fixed since then… but this was my issue.   I noticed this email and remembered the pain of solving this so I thought I’d pipe up.

Thank you  gjaman for the tips and explanation. Before I insert into the row i check if the image exist. Now I don’t see the images getting stuck in the top .

if params.img then if cacheFileExists(filename) then local img=display.newImageRect(filename, system.TemporaryDirectory,100,100) img.x=0 img.y=0 img.anchorX=0 img.anchorY=0 row:insert(img) else display.loadRemoteImage(params.img, "GET", thumbListener, filename, system.TemporaryDirectory,0, 0 ) end end

Hi David,

I’m not sure why images are getting “stuck” (it may be some aspect of your code), but generally speaking, you’re not going to achieve smooth tableView scrolling with remotely-loaded images unless you preload them first. If the tableView constantly needs to “request” an image via network each time it’s about to come into view, it will lag, especially if the user scrolls very fast. If possible, you need to figure out a way to pre-load all of the images, or (if this is impossible for some design reason), pre-load a certain number of them which you’ll know are going to come into view, then load another chunk behind the scenes, and so forth.

Hope this helps somewhat,

Brent

Thank you for the reply. I will try - display 10 items and pre load images then add lazy loading …

I’ve seen lots of iphone app which has tons of images in a table and it loads smoothly… all images has preloader and they look professional. Is this a Corona limitation.

Here is code -

function displayData(id) myList=json.decode(loadValue(id..'.txt')); for key,value in pairs(myList.data) do --local isCategory = false local rowHeight = 250 -- local rowColor = { tableView:insertRow { rowHeight = rowHeight, isCategory = false, rowColor = { 1, 1, 1 }, lineColor = { 0.90, 0.90, 0.90 }, params = { title = myList.data[key].title, price = myList.data[key].price, price2 = myList.data[key].price2, desc = myList.data[key].sdesc, img = myList.data[key].img, imgfile = myList.data[key].imgfile, thumb = myList.data[key].thumb } } end end local function onRowRender( event ) local phase = event.phase local row = event.row local params = event.row.params local filename = params.imgfile local function thumbListener( event ) if ( event.isError ) then else event.target.alpha = 0 -- -- This is scaling code. I have no idea how big the downloaded image was. -- Divide the desired height of the image by the real height and that gives us a number we -- can feed to the scale() method to keep the image's aspect ratio and controlling the height. -- If you need to furhter control the width, you could do a second pass kind of like this: -- -- if w \* s \> maxWidth then s = maxWidth / w end -- -- and feed the new s value to the scale() method. -- local w = event.target.width --print(w..display.contentWidth) local h = event.target.height local s = 100 / h local offset=0 if w \> display.contentWidth then local diff = w-display.contentWidth; offset = math.abs(display.contentWidth-diff/2); print(w..display.contentWidth..offset) else offset = display.contentWidth-w end event.target:scale(s,s) event.target.anchorX = 0 event.target.anchorY = 0 event.target.x =0 event.target.y = 0 -- -- put the image into the row -- row:insert(event.target) event.target.alpha=1 --transition.to( event.target, {time=100, alpha = 1.0 } ) end end -- downloadFile(params.thumb,completionListener) local groupContentHeight = row.contentHeight if params.img then display.loadRemoteImage(params.img, "GET", thumbListener, filename, system.CachesDirectory, 0, 0 ) end if params.price then local rowPrice = display.newText( row, params.price, 0, 0,240, 0, myApp.font,18) rowPrice.x = display.contentWidth-60 rowPrice.anchorX = 0 rowPrice.y =groupContentHeight \* 0.85 rowPrice:setFillColor(0,0,0) if params.price2 then local rowPrice2 = display.newText( row, params.price2, 0, 0,240, 0, myApp.font,14) rowPrice2.x = display.contentWidth-60 rowPrice2.anchorX = 0 rowPrice2.y =groupContentHeight \* 0.91 rowPrice2:setFillColor(0,0,0) end local rowTitle = display.newText( row, params.title, 0, 0,240, 0, myApp.font,15) rowTitle.x = 10 rowTitle.anchorX = 0 rowTitle.y =groupContentHeight \* 0.9 rowTitle:setFillColor(0,0,0) end end

The problem is rows are destroyed when they are out of view.  When the row is in view it calls the the render function, which initiates the load remote image.  When the row is out of focus it gets destroyed. The load remote image handler is trying to add it to a group that no longer exists, so it get pushed into the default group.

In my app I did some debugging and noticed there are properties I could check to see if the row was not destroyed yet.  I picked the _proxy.

see http://forums.coronalabs.com/topic/44839-newtableview-asynchronous-lazy-loading-with-loadremoteimage/#entry233771

You don’t want the image downloaded each time the row comes in/out of focus, so you’ll want to save it in the temp dir and check if the file exists first before downloading.

I have some code that does all this somewhere, but I haven’t touch corona for 4 months.  Maybe something has been fixed since then… but this was my issue.   I noticed this email and remembered the pain of solving this so I thought I’d pipe up.

Thank you  gjaman for the tips and explanation. Before I insert into the row i check if the image exist. Now I don’t see the images getting stuck in the top .

if params.img then if cacheFileExists(filename) then local img=display.newImageRect(filename, system.TemporaryDirectory,100,100) img.x=0 img.y=0 img.anchorX=0 img.anchorY=0 row:insert(img) else display.loadRemoteImage(params.img, "GET", thumbListener, filename, system.TemporaryDirectory,0, 0 ) end end