tableview micro stuttering

Tableviews in Corona depresses me. 

Scrolling tableviews with images have lots of micro stuttering. it’s not a smooth scroll experience like I see on other native apps. I’ve one of the fastest android smartphones on the planet and when i scroll tableviews it looks like an old zx spectrum (good old days) 

The only way I can do smooth scrolls is caching images first on memory then scrolling them. but this is a limit option since memory is limited. in large lists won’t work.

I think the problem is, since tableviews remove rows and create rows that are not beeing showed (a good approach), removing and creating images is just to intensive cpu use, for having a smooth scroll on Corona.

So my question is, is it possible to have tableview scroll experience flawless like native apps?

I could create myself a “lite” version of a tableview, but i think the result would be the same, because of the “create”, “delete” images intensive cpu use.

anyone like me out there that likes smooth apps resolved this problem?

Corona is doing anything to speed their code? (if that is possible, ofc)

Regards,

Carlos.

Can you post a boiled-down version of your code which demonstrates this stuttering?

Personally, I wouldn’t use a tableview for scrolling images; I’d use scrollview.

I have not seen the stuttering you mention in the widgets myself so, for a powerful device, I wonder if you are attempting to load the images into the tableview as the scroll is happening. Is this what you’re doing? If not, it could well be because the tableview does management of what is in the table itself.

ScrollView does not do that and you are free to manage the view item’s children as you wish.

Personally, I really like the idea of the Table View, but every time I’ve tried to implement something with it I’ve fallen back to modifying the ScrollView. Never for performance reasons, I have to say.

@horacebury, any tableview with images will have those micro shuttering done in corona. even a simple one. it’s just a matter of beeing meticulous. you will notice more on android devices than apple ones. but it exists on both. all scroll menus i’ve, where made by me (not using scrollviews or tableviews, and even the delta formulas are made by me) and when i had to remove objects and create them, i had this problem also (less visible but still present). the solution passes to put all images on a sheet, or caching the images on memory like i said. but a tableview that gets images from the internet and show them, we can’t use none of those methods.

what i do is cache the images on a tempory directory so next time will go the cached image and not to the internet. but still the problem is the same…removing and creating objects…using scrollview with more than 100 images would probably crash the app. the tableview approach that deletes and create objects as they are showed on screen is the correct approach.

i’ve done a simple car dealer app. listing all cars with images, price and kms, so the user can press one and see details if they like it. all works fine, less the tableview, that i really hate because of those stutterings. if i show the app to some they don’t even notice or if they do, they don’t care about problem, but the client noticed and didn’t liked also. 

Network downloads takes time. Reading a file in, opening it and making a texture out of it takes time. The more you can cache the better, the more you can pre-load the better.

As far as tableViews go, you can’t have both light memory usage by culling off screen rows and the speed from having off screen rows unculled. 

Rob

@Rob Miracle, the stuttering appears in simple tableviews without going to internet, just having images. it’s just a problem of deleting and creating images that corona struggles with.

i can’t preload 100 images. i’ve done that on a car dealer that have no more than 30 cars, and the tableview is smooth, but will crash on ipad mini 2, on ipad mini 4 it works fine. this new client have more than 100 cars. i’ve filters, but the main list will be large.

about going for internet getting images, etc. other apps i see do exactly the same i do…their tables are smooth with lists with more than 100 elements. blazing fast when i scroll in my device…when i see my table, i get depressed…even if i do a simple tableview with local images to test it will stuttering. 

What I do with scrollViews with hundreds of images (that can’t fit on an atlas) is to load the textures and then only render them on demand.  It is the best compromise between memory usage and speed/smoothness.  

This works great if the images are known.  If they are unknown you will need to implement a read ahead buffer that starts the network request say 10 rows in advance unlike the Corona implementation that only checks 1 row in advance.

@carloscosta,

As noted, populating a TableView with a lot of images – on-the-fly as you scroll very fast – can cause a stutter because those images need to be loaded into memory as they are about to enter the view. This is especially true if the images are larger in size.

This is why we offer methods like pre-loading textures. At some point before they’re needed, you can pre-load all of your images into memory and then, when the TableView needs to show them, they’ll be instantly available without any performance impact.

See this guide on how to accomplish this.

https://docs.coronalabs.com/guide/graphics/textureManagement.html

In particular, this example in that guide shows you a simplified way of handling it:

https://docs.coronalabs.com/guide/graphics/textureManagement.html#pre-loading-images

Take care,

Brent

Af for pre-loading 100 images, that shouldn’t be “unreasonable”. How large are these images in file size and pixel dimensions?

@Brent, the images are about 1024x608 (don’t have exact resolution right now but its about this resolution. size i don’t have right now, i’m at home, tomorrow i will let you know, its 00.17am here). 

if you read my last post, you will notice that i already tried texturing the images. thanks for the tip anyway.

it is “unreasonable” because i tried it with a car dealer with ± 30 cars and it failed on ipad mini 2. it just crashes the app. on any newer ipad or iphone it will work fine (again with 30 only images). the client still prefered that than the stutter.

in this case, the car dealer have about 135 cars. i doubt i can cache them all like i did in the previews project.

the stutter, apears even if i scroll very  slow. even when i stop press the screen and let the scroll ends by it self when slowing down you will notice the stutter. i just mention scrolling fast, because i saw others codes doing exact same think than mine, passing with flying colors at a very high rate of scrolling.

@sphere, texturing images i already tried and it’s true, it will make a smooth scroll experience. the problem is that i already tried with 30 images and it failed on ipad 2 mini. if i triple the formula, i wonder if it will fail on more devices. 90% of the persons in my country have mid low end devices. 550euros its a month work to 60% of the persons here.

buffering 10 images, did you tried that formula? because it looks the same as buffering 1. if you pass 1 row. you will only have 9 images and you will need to get another to get the 10 image cached. so the problem is the same as having 1 buffering.

even if i implement a sistem that will cache 10, and only when they run out it will load a new stack of 10 images (like an ebook reader do)…it will stutter at that moment (like and ebook reader do)…and passing 10 images its takes kinda 2seconds…it will stutter on that moment also…if i’m missing something please let me know.

@Brent, if you notice the other programmers in this topic, you will notice that none uses tableviews. i guess i’m not alone in this boat. any help in this department so we all could benefit from it, i will humbly appreciate.

regards,

Carlos

Hi Carlos,

Yes, pre-loading 30+ images of ~1024x608 will occupy a vast amount of texture memory, likely crashing on certain devices with less texture memory. This would occur regardless of if you’re using a TableView or not.

I imagine that you’d only be showing a “preview” or “thumbnail” of the cars in the TableView? Certainly not the full 1024x608 version? If so, the best way to solve this would be to have a smaller set of images for displaying in the TableView, and pre-load them. Then when the user clicks over to (I assume) a more detailed page, you load the full-size image. Would that work for you?

I’m not sure that “native” apps would be able to handle caching that many images of those large dimensions either, nor loading them on-the-fly during fast scrolling without some performance impact. That’s just a lot of texture data to be loading.

Best regards,

Brent

@carlos, few things you could do.  Perhaps approach this as a 2-pass implementation.  Clearly you are trying to display a list of cars for sale from an internet source.  So you could have a first pass that just returned a list of all the image URLs that would be displayed and you have a background thread (look into co-routines for this as Corona is not multi-threaded) and then the second pass will generate your list.

Loading images from device will be way quicker than waiting for a network download so to achieve what you want you will need to split out your processes.

I would take this a stage further and when the network download is complete then preload the image into a texture, then when the row comes into view you simple paint that onto a newRect().  This is about as fast as you are going to get.

In my game I have scrollViews loading 100+ images in this way and they show no stutter whilst lazy loading.

Now, to my read ahead buffer idea.

What I meant was the standard behaviour is Corona will load the row just about to come into view - this is what causes the stutter. You could mod the tableView library to look 10 rows ahead and preload that graphic.  Yes the load time will still be the same but users are likely to scroll slowly reading as they go.  You are just buffering to ensure if they swipe a bit quick you have the next 10 images already buffered.

Standard Corona is great up to a point… then you need to extend the default behaviour.

Carlos, everything you’re saying seems to imply that what you’re trying to do is - to your mind - reasonable but what you’re saying that you are doing is actually impractical. All the posts above have shown you where the problem lies and what potential solutions are available.

If you are insisting on using a TableView and, even with small images which are loaded into memory beforehand, it performs badly, you should very seriously think about using ScrollView.

But then, why are you insisting on using a mechanism which obviously is not working for you?

I can ask the same question of the images, in fact: Why are you trying to load full screen images and display them on a small screen. You definitely don’t need to be doing that. Even if you need large size images, I’m sure they could be smaller in size.

If you have control over the server side you should be providing the images in a smaller size/format before they get uploaded. If not, you should probably scale them down prior to display, for memory and performance.

If you are developing an app which has the principle function (whether the user considers it this is a different question) of displaying images you should be considering all your options. There’s lots of good advice above, for example.

@Brent, the 1024x608 image is the preview. inside the car details, you will have more photos from the same car. I opted for that resolution, because of screen resolutions these days are getting bigger ever day (mine is 1440x2560). An image in cars is very important and they were all taken by professional photographers. I don’t want to ruin they work putting low-quality photos, doing that blurred effect of zooming photos with lower resolution. even said that I already tried very small images, with a small resolution to try it if that matter. and I still had the micro stuttering, less visible, it’s true, but not smooth so I opted to a better-looking experience to the user since they will have the stutter anyway.

I see other apps having the same problem than mine, others without it. all with the same approach.

what I do in the app is, I go to the Internet, get the list of the images, create the tableview after, while scrolling I check if the photo is on the device, if it’s not I will download it, while downloading I will present a “dummy” photo  (black and white). when the download is ready it will substitute for the new image.

it works better than i was expecting because I get about the same performance than eliminating the all network part and creating a tableview only with local images.

lowering resolution will not solve the problem will only minimize it, which is good, but it will ruin the layout. thanks for the tips anyway, i really appreciate.

@horacebury, it’s doable, because I saw it done. maybe is not doable on Corona, that is what I’m debating here, if any internal change on corona part can make things happen faster, I tried all I could think of on my side. and all suggestions till now, I’ve done them all less 1 which I will today.

How many rows do you have on screen at once? I can’t imagine the native apps you are talking about are rendering lots of images of that resolution on the fly.

Could you not have low resolution versions for use in general scrolling, and as soon as the user stops scrolling or zooms in, start to replace the ‘preview’ with the high-res versions.

Hi Carlos,

As you say, a large screen is ~2560 pixels tall. That would be a modern + more powerful device and, because it has such a large resolution, it should (must) have a larger maximum amount of texture memory. So, you can use larger images on that device… but on an old device like the iPad 2 (now about 6 years old?), the resolution is much smaller… so you should not be using incredibly large images on that device.

This is how Corona’s dynamic image selection feature can help you. For smaller screens, you should load smaller images, which will prevent the texture memory from exceeding the maximum and crashing. After all, the screen on the iPad 2 is just 1024 pixels tall and 768 pixels wide, so you don’t need images that are nearly as large as the entire screen on that device.

This will, of course, be more effort on your side because you’ll need to create a different “set” of all images from the professional photographers. However, it should prevent your app from crashing on older devices with smaller screens or lower texture memory.

Brent

@Sphere Game Studios, the 2-pass implementation, I already did that with the same result. getting images from the devices will stutter anyway, that’s what I’m trying to debate here…forget the internet part. that I can handle without a performance hit.

I think you touched the point here. Corona is not multithread.

Putting images inside a newRect is faster than creating a newImageRect? I will try that.

I will give it a try to the scrollView approach again. Thanks for the tips.

@Brent, I sad ipad mini 2, not ipad 2. the resolution of ipad mini 2 is 2048x1536 px. I guess 1024x608 images (i show 2 and a half pictures per screen) are not that large. I scale them down on lower resolution devices. i used to have 3 images resolutions for each image, on older projects. i stopped doing that because I didn’t see any performance impact on scaling the larger image to a lower size on lower resolution devices. like i told you, i did try with lower resolutions pictures with the same result. creating and deleting images on Corona is too CPU intensive. if you can’t do much on your side, i will try to explore more the textures part, which i had success to some extent. maybe i will try to cache to some point, and flush it if it passes that point so it would not crash on older devices.

Is there something about TableView which means you must use TableView?