[TIMOB-3004] Android: Remote images in tableview cause performance issues while scrolling
GitHub Issue | n/a |
---|---|
Type | Bug |
Priority | Medium |
Status | Closed |
Resolution | Fixed |
Resolution Date | 2011-04-17T02:00:39.000+0000 |
Affected Version/s | n/a |
Fix Version/s | Release 1.6.0 M10 |
Components | Android |
Labels | android, cache, defect, imagecache, release-1.6.0, reported-1.6.0, responsecache, rplist |
Reporter | Rick Blalock |
Assignee | Don Thorp |
Created | 2011-04-15T03:34:30.000+0000 |
Updated | 2011-04-17T02:00:39.000+0000 |
Description
I tested the lighthouse ticket here - https://appcelerator.lighthouseapp.com/projects/32238/tickets/1508-android-remote-images-in-imageview-get-reloaded-inside-a-tableviewrow"> https://appcelerator.lighthouseapp.com/projects/32238/tickets/1508-... - with the latest build from today on my Galaxy (Android 2.2). The images now show up but the table performance while scrolling is odd.
Using the KS RSS XML example: You'll see the images there but
when scrolling it jitter-scrolls down slowly and then rapidly
scrolls to the end as if it's catching up to where it is supposed
to be. Sometimes doing a slow scroll it will stay in place or jump
to where it should be, making it look like a scroll didn't
happen.
I'm debugging an HD ticket that is having the issue as well. I'll
get specifics from him on how his table is performing. http://developer.appcelerator.com/helpdesk/view/67491">http://developer.appcelerator.com/helpdesk/view/67491
Tested - Android 2.2 Galaxy, Ti 1.6 CI
Anecdotal evidence provided by Q&A user in http://developer.appcelerator.com/question/112581/tableview-with-images-really-slow"> this post.
Summary of observations/isuses with tableviews containing rows with remote images:
According to user, this behavior seemed to be introduced with 1.5.X, as tableviews in 1.4.X were fast.
Definitely not a low priority bug. A good number of applications today have a list view with images. This bug makes the app really slow. Could we please request you to revisit the priority of this bug and atleast it review it for 1.6.
Kevin Whinery also knows about the issue given that he faced similar problems with Tweetanium. He can also provide insight into this issue.
Thank you.
Discuss in http://developer.appcelerator.com/question/112581/tableview-with-images-really-slow"> http://developer.appcelerator.com/question/112581/tableview-with-im...
@Bill, Thanks for a fabulous writeup. Truly appreciate it and great work!!
@Don, Given that this has been reproducible at your end & a good number of us are facing it, if you could prioritize this it would be greatly appreciated.
Thanks for your support folks!
(from [135e4b8c60bd09d3cc2982b91500b870709c6e9a]) [#3004] Introduce a few efficiencies when loading images. Cache the bounds of the image source; be more selective when processProperties tries to reload an image. https://github.com/appcelerator/titanium_mobile/commit/135e4b8c60bd09d3cc2982b91500b870709c6e9a"> https://github.com/appcelerator/titanium_mobile/commit/135e4b8c60bd...
@Bill - Another input that might help you.
Assume there are 25 rows to be in the view - Only 5 or 6 rows are visible in the screen. prior to 1.5 when we were using different classnames - only the 5 images would be loaded and the remaining would be fetched but would be loaded onto the screen as we scroll.(Loading them as the user works! & scrolling used blazing fast)
But with 1.5.X/1.6.X (with caching fixes we assume) all the images are fetched & seem to be loaded. This can be seen especially when cached.
In our testing and our app, this makes a huge impact.
May be you could try YQL sample(with more rows say 25) with different ids in 1.4.x to see what we mean. 1.4.x didnt have caching & had rows disappearing if you used the same classname.
If you still more info, we could create a sample data with our data. Hope this information helps you. Thanks!
(from [316c2c7353ff133e9d0df771730ec0c9fd197ed0]) cache image view bitmaps internally in the image view proxy when they're reused inside a table view. decrease the number of fixed threads for the
download manager to 2, and move the response cache cleanup to a single
threaded interval based pool. [#3004]
https://github.com/appcelerator/titanium_mobile/commit/316c2c7353ff133e9d0df771730ec0c9fd197ed0"> https://github.com/appcelerator/titanium_mobile/commit/316c2c7353ff...
(from [1622245cb500224a86a1bd15dbfb423e62a9551d]) [#3004] Introduce a few efficiencies when loading images. Cache the bounds of the image source; be more selective when processProperties tries to reload an image. https://github.com/appcelerator/titanium_mobile/commit/1622245cb500224a86a1bd15dbfb423e62a9551d"> https://github.com/appcelerator/titanium_mobile/commit/1622245cb500...
(from [34fd3aead2d4e3a21197ca22142856e62809b4e6]) cache image view bitmaps internally in the image view proxy when they're reused inside a table view. decrease the number of fixed threads for the
download manager to 2, and move the response cache cleanup to a single
threaded interval based pool. [#3004]
https://github.com/appcelerator/titanium_mobile/commit/34fd3aead2d4e3a21197ca22142856e62809b4e6"> https://github.com/appcelerator/titanium_mobile/commit/34fd3aead2d4...
We now have a two-level cache for remote images, the first level being in memory, which improves scrolling. We also removed some inefficiencies that were present when we load an image from the 2nd-level cache (the Http response cache). And we got the code into 1.6.0, which I'm very pleased about :) . That's all we'll do at this time, as 1.6.0 is "closed".
People can check out the changes by ...
pulling from our 1_6_X branch if you're adept at building from source, or...
downloading from our http://guides.appcelerator.com/en/continuous_builds.html">continuous build server
@Taazza: I'm not seeing that behavior. I can definitely see "lower" images (the ones I'm reaching as I scroll down) loading on my way down. They definitely don't all load right away. The row of a table view -- including its constituents like any ImageViews you play plop in them -- don't come into existence into they become visible. You can see this if you turn on our debug flag by putting setting the ti.android.debug property to true in tiapp.xml:
Then at the command-line do...
Then open the window containing your table view. When it finishes opening, count the number of grep'd lines. It will be less than the number of rows in your table (assuming your table has rows that extend off screen). I believe it's going to be the number of visible rows plus one, but I'm not entirely certain about that.
Anyway try the new code, hopefully you'll see an improvement.
@Bill - Sounds good. Will try it out in a couple of hours and get back to you with the feedback. Awesome of you to push this in so quickly. Cheers!
Still seeing the same issue with images that are already cached. Will try your steps by enabling the debug log. BTW also seeing a crash:
Sending event: exception on thread: main msg:java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@4428c9e8; Titanium 1.6.0,2011/02/17 16:34,4fd3ae...
[TRACE] E/TiUncaughtHandler( 331): java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@4428c9e8 [TRACE] E/TiUncaughtHandler( 331): at android.graphics.Canvas.throwIfRecycled(Canvas.java:955) [TRACE] E/TiUncaughtHandler( 331): at android.graphics.Canvas.drawBitmap(Canvas.java:1044) [TRACE] E/TiUncaughtHandler( 331): at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:323) [TRACE] E/TiUncaughtHandler( 331): at android.widget.ImageView.onDraw(ImageView.java:860) [TRACE] E/TiUncaughtHandler( 331): at android.view.View.draw(View.java:6740) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewGroup.drawChild(ViewGroup.java:1640) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewGroup.drawChild(ViewGroup.java:1638) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewGroup.drawChild(ViewGroup.java:1638) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) [TRACE] E/TiUncaughtHandler( 331): at android.view.View.draw(View.java:6743) [TRACE] E/TiUncaughtHandler( 331): at android.view.View.buildDrawingCache(View.java:6502) [TRACE] E/TiUncaughtHandler( 331): at android.view.View.getDrawingCache(View.java:6288) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewGroup.drawChild(ViewGroup.java:1565) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) [TRACE] E/TiUncaughtHandler( 331): at android.widget.AbsListView.dispatchDraw(AbsListView.java:1365) [TRACE] E/TiUncaughtHandler( 331): at android.widget.ListView.dispatchDraw(ListView.java:3046) [TRACE] E/TiUncaughtHandler( 331): at android.view.View.draw(View.java:6846) [TRACE] E/TiUncaughtHandler( 331): at android.widget.AbsListView.draw(AbsListView.java:2257) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewGroup.drawChild(ViewGroup.java:1640) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewGroup.drawChild(ViewGroup.java:1638) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewGroup.drawChild(ViewGroup.java:1638) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) [TRACE] E/TiUncaughtHandler( 331): at android.view.View.draw(View.java:6743) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewGroup.drawChild(ViewGroup.java:1640) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewGroup.drawChild(ViewGroup.java:1638) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) [TRACE] E/TiUncaughtHandler( 331): at android.view.View.draw(View.java:6743) [TRACE] E/TiUncaughtHandler( 331): at android.widget.FrameLayout.draw(FrameLayout.java:352) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewGroup.drawChild(ViewGroup.java:1640) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) [TRACE] E/TiUncaughtHandler( 331): at android.view.View.draw(View.java:6743) [TRACE] E/TiUncaughtHandler( 331): at android.widget.FrameLayout.draw(FrameLayout.java:352) [TRACE] E/TiUncaughtHandler( 331): at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1842) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewRoot.draw(ViewRoot.java:1407) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewRoot.performTraversals(ViewRoot.java:1163) [TRACE] E/TiUncaughtHandler( 331): at android.view.ViewRoot.handleMessage(ViewRoot.java:1727) [TRACE] E/TiUncaughtHandler( 331): at android.os.Handler.dispatchMessage(Handler.java:99) [TRACE] E/TiUncaughtHandler( 331): at android.os.Looper.loop(Looper.java:123) [TRACE] E/TiUncaughtHandler( 331): at android.app.ActivityThread.main(ActivityThread.java:4627) [TRACE] E/TiUncaughtHandler( 331): at java.lang.reflect.Method.invokeNative(Native Method) [TRACE] E/TiUncaughtHandler( 331): at java.lang.reflect.Method.invoke(Method.java:521) [TRACE] E/TiUncaughtHandler( 331): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868) [TRACE] E/TiUncaughtHandler( 331): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626) [TRACE] E/TiUncaughtHandler( 331): at dalvik.system.NativeStart.main(Native Method) [TRACE] E/AndroidRuntime( 331): FATAL EXCEPTION: main [TRACE] E/AndroidRuntime( 331): java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@4428c9e8 [TRACE] E/AndroidRuntime( 331): at android.graphics.Canvas.throwIfRecycled(Canvas.java:955) [TRACE] E/AndroidRuntime( 331): at android.graphics.Canvas.drawBitmap(Canvas.java:1044) [TRACE] E/AndroidRuntime( 331): at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:323) [TRACE] E/AndroidRuntime( 331): at android.widget.ImageView.onDraw(ImageView.java:860) [TRACE] E/AndroidRuntime( 331): at android.view.View.draw(View.java:6740) [TRACE] E/AndroidRuntime( 331): at android.view.ViewGroup.drawChild(ViewGroup.java:1640) [TRACE] E/AndroidRuntime( 331): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) [TRACE] E/AndroidRuntime( 331): at android.view.ViewGroup.drawChild(ViewGroup.java:1638) [TRACE] E/AndroidRuntime( 331): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) [TRACE] E/AndroidRuntime( 331): at android.view.ViewGroup.drawChild(ViewGroup.java:1638) [TRACE] E/AndroidRuntime( 331): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) [TRACE] E/AndroidRuntime( 331): at android.view.View.draw(View.java:6743) [TRACE] E/AndroidRuntime( 331): at android.view.View.buildDrawingCache(View.java:6502) [TRACE] E/AndroidRuntime( 331): at android.view.View.getDrawingCache(View.java:6288) [TRACE] E/AndroidRuntime( 331): at android.view.ViewGroup.drawChild(ViewGroup.java:1565) [TRACE] E/AndroidRuntime( 331): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) [TRACE] E/AndroidRuntime( 331): at android.widget.AbsListView.dispatchDraw(AbsListView.java:1365) [TRACE] E/AndroidRuntime( 331): at android.widget.ListView.dispatchDraw(ListView.java:3046) [TRACE] E/AndroidRuntime( 331): at android.view.View.draw(View.java:6846) [TRACE] E/AndroidRuntime( 331): at android.widget.AbsListView.draw(AbsListView.java:2257) [TRACE] E/AndroidRuntime( 331): at android.view.ViewGroup.drawChild(ViewGroup.java:1640) [TRACE] E/AndroidRuntime( 331): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) [TRACE] E/AndroidRuntime( 331): at android.view.ViewGroup.drawChild(ViewGroup.java:1638) [TRACE] E/AndroidRuntime( 331): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) [TRACE] E/AndroidRuntime( 331): at android.view.ViewGroup.drawChild(ViewGroup.java:1638) [TRACE] E/AndroidRuntime( 331): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) [TRACE] E/AndroidRuntime( 331): at android.view.View.draw(View.java:6743) [TRACE] E/AndroidRuntime( 331): at android.view.ViewGroup.drawChild(ViewGroup.java:1640) [TRACE] E/AndroidRuntime( 331): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) [TRACE] E/AndroidRuntime( 331): at android.view.ViewGroup.drawChild(ViewGroup.java:1638) [TRACE] E/AndroidRuntime( 331): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) [TRACE] E/AndroidRuntime( 331): at android.view.View.draw(View.java:6743) [TRACE] E/AndroidRuntime( 331): at android.widget.FrameLayout.draw(FrameLayout.java:352) [TRACE] E/AndroidRuntime( 331): at android.view.ViewGroup.drawChild(ViewGroup.java:1640) [TRACE] E/AndroidRuntime( 331): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1367) [TRACE] E/AndroidRuntime( 331): at android.view.View.draw(View.java:6743) [TRACE] E/AndroidRuntime( 331): at android.widget.FrameLayout.draw(FrameLayout.java:352) [TRACE] E/AndroidRuntime( 331): at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1842) [TRACE] E/AndroidRuntime( 331): at android.view.ViewRoot.draw(ViewRoot.java:1407) [TRACE] E/AndroidRuntime( 331): at android.view.ViewRoot.performTraversals(ViewRoot.java:1163) [TRACE] E/AndroidRuntime( 331): at android.view.ViewRoot.handleMessage(ViewRoot.java:1727) [TRACE] E/AndroidRuntime( 331): at android.os.Handler.dispatchMessage(Handler.java:99) [TRACE] E/AndroidRuntime( 331): at android.os.Looper.loop(Looper.java:123) [TRACE] E/AndroidRuntime( 331): at android.app.ActivityThread.main(ActivityThread.java:4627) [TRACE] E/AndroidRuntime( 331): at java.lang.reflect.Method.invokeNative(Native Method) [TRACE] E/AndroidRuntime( 331): at java.lang.reflect.Method.invoke(Method.java:521) [TRACE] E/AndroidRuntime( 331): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868) [TRACE] E/AndroidRuntime( 331): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626) [TRACE] E/AndroidRuntime( 331): at dalvik.system.NativeStart.main(Native Method) [TRACE] W/ActivityManager( 61): Force finishing activity com.test.go/org.appcelerator.titanium.TiActivity
(from [00031c56940152ffde9ffd59f7a930a71ae0fb31]) don't overzealously recycle bitmaps that we're reusing from network sources, fixing a runtime error [#3004]
https://github.com/appcelerator/titanium_mobile/commit/00031c56940152ffde9ffd59f7a930a71ae0fb31"> https://github.com/appcelerator/titanium_mobile/commit/00031c569401...
(from [929334e270c137a8839117a90f513e8ba423b75c]) don't overzealously recycle bitmaps that we're reusing from network sources, fixing a runtime error [#3004]
https://github.com/appcelerator/titanium_mobile/commit/929334e270c137a8839117a90f513e8ba423b75c"> https://github.com/appcelerator/titanium_mobile/commit/929334e270c1...
@Bill: So here's how things stand, you idea of using adb logcat was very helpful. The issue seems to be not of images but of use of appendRow. Scrolling doesnt happen when you use appendRow instead of setData. We have been able to reproduce the issue with your YQL_FLICKR example, pls find the gist below
https://gist.github.com/4c226b378d20ec7f76ef">https://gist.github.com/4c226b378d20ec7f76ef
The same code used to work in 1.4.X. We also trying to double check the same at our end. Will post an update soon. Meanwhile if you have more insight into this problem pls let us know.
@Bill One cant scroll till entire table is loaded when using appendRow and scrolling seems sluggish when compared to setData. Can be reproduced with the YQL_FLICKR sample as well.
One could always use setData but perceived performance is no good. A good number of fixes have gone in 1.6.X. Unfortunately we dont have access to 1.4.1 which is where we saw the performance of scrolling the same table.
Look forward to hearing from you.
closing resolved against KS RSS XML test case behavior, GA build galaxy tab (2.2.2) and G1 (1.6).
Taazza, it's best to use helpdesk/Q&A for any issues you are encountering.