tableview micro stuttering

HI Carlos,

I see… iPad Mini 2 (not iPad 2)… but regardless of anything else, this is an issue of texture memory, not Corona, not TableView vs. ScrollView, not really anything else. If you attempt to load 30-135 images of 1024x608 into memory, all at the same time, you will exceed almost any device’s texture memory and it will crash. There’s simply no realistic way around that.

The reason the Corona TableView was designed to load rows “near when they become visible” is exactly for this reason: some people want TableViews with 500, 1000, or even more rows, and it’s impossible (or hardware limited) to keep that many rows in memory at the same time. Thus, it dynamically loads rows when they’re about to come into view… but if you attempt to load huge images into each row, it will stutter while loading.

ScrollView probably won’t help you much, since you’d still be loading in more images than devices like the iPad Mini 2 can technically handle, based on the actual hardware limitations (not Corona’s).

I’m not sure what else we can advise at this point. You want the highest resolution images possible, and 30-135 of them in memory at the same time, but you also want to run this on somewhat older devices with less texture memory. My suggestion of using lower-resolution images on those devices should help you, but that’s about the only possibility I can imagine considering your goals.

Best regards,

Brent

@carlos, I have an idea if you can do it.  Create an HTML page in the format that you want (with the images and text) and then load that into webView and see what the performance is like.  You can perfectly emulate a tableView schema like this and you may well find it is a lot smoother.

You can then intercept the click in Corona and then move to your “more details” scene or pop and overlay or whatever.

Posting some code wouldn’t hurt, either.

@Brent, your absolutely right, I can’t put 100 “hight” quality pictures on memory. I’m saying that since my second post (guess no one reads them till the end or my poor English is not letting people understand that).

TableView, is the correct approach, exactly for what you pointed, that’s why I’m using it.

I want 35-100 images, but I don’t want them all in memory (that method is what you suggested and i told that i could not do that for the reasons you know undertand).

i just want a tableview without the stutter. like i told more than 1 time (guess my poor English) having lower resolution pictures won’t solve the problem. I tried that. having 30 or 10000 images should not be an issue because the tableview approach doesn’t depend on the number of elements of the list. the problem is that corona is to slow to render/deleting images, so we need to use alternatives like caching images first which destroys the proposed of the tableview on the first place. if the render/deleting images was faster on corona this problem was not happening and we were not having this discussion. On Corona, defense, like I said, I see this problem on other apps also that don’t use Corona. But i see smooth scrolls also. So I know it’s possible (maybe not on Corona).

@Sphere, that’s a great advice. But I will try first using scrollviews and caching images the most i can (like you suggested) to see if i minimize the problem to an extent i’m happy with. if not, i will try the webview solution.

Hi,

I also get this micro stuttering and have been trying to find the cause.

My images are only 30x30 pixels, one for each row.

  1. Changing the widget code to preload earlier didnt help much (2 lines that need modification)
  2. Downloading on the fly vs downloading before inserting made practically no difference (on a 2MB connection)
  3. Inserting new rows in batches vs on demand, made little difference.
  4. Using fill.paint is perhaps the method that seem to make a slight difference, but it doesnt remove the stutter on an android tab (Samsung A6)

The culling does not help with the stuttering or the slowdown which progressivly happens as the list gets longer (made it autoscroll indefinately on my device). I notice that what takes longer and longer time is inserting rows, and this is noticeable already after a few hundred lines.

One thing which I did notice is that even with culling, the stutter seem to only occur when new rows are added to the table. Scrolling up and down existing rows works great. I am not technical enough to know how memory management works on devices so perhaps there is some buffering or cache at work which could explain this, or not.

I’ll keep testing if I can think of something else, in the meantime I have to rescue my pizza that should be overdone by now ^^

EDIT, too late! what was once a pizza is now a dark suspicious looking cracker  :wacko:

using graphics.newTexture, I was able to “eliminate” the stuttering from tableviews, but I can only use it on small tableviews because it will crash any app if you pre cache a lot of large images.

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.