Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-3004] Android: Remote images in tableview cause performance issues while scrolling

GitHub Issuen/a
TypeBug
PriorityMedium
StatusClosed
ResolutionFixed
Resolution Date2011-04-17T02:00:39.000+0000
Affected Version/sn/a
Fix Version/sRelease 1.6.0 M10
ComponentsAndroid
Labelsandroid, cache, defect, imagecache, release-1.6.0, reported-1.6.0, responsecache, rplist
ReporterRick Blalock
AssigneeDon Thorp
Created2011-04-15T03:34:30.000+0000
Updated2011-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

Comments

  1. hal 2011-04-15

    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:

    • images loaded for rows that are off-screen, causing delay before user can interact with it
    • table not scrollable until all rows are loaded

    According to user, this behavior seemed to be introduced with 1.5.X, as tableviews in 1.4.X were fast.

  2. Taazza 2011-04-15

    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.

  3. Bill Dawson 2011-04-15

    Discuss in http://developer.appcelerator.com/question/112581/tableview-with-images-really-slow"> http://developer.appcelerator.com/question/112581/tableview-with-im...

  4. Taazza 2011-04-15

    @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!

  5. Bill Dawson 2011-04-15

    (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...

  6. Taazza 2011-04-15

    @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!

  7. Marshall Culpepper 2011-04-15

    (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...

  8. Bill Dawson 2011-04-15

    (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...

  9. Marshall Culpepper 2011-04-15

    (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...

  10. Bill Dawson 2011-04-15

    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 ...

    @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:

        <property type="bool" name="ti.android.debug">true</property>
        

    Then at the command-line do...

        adb logcat | grep "Creating an ImageView"
        

    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.

  11. Taazza 2011-04-15

    @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!

  12. Taazza 2011-04-15

    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

  13. Marshall Culpepper 2011-04-15

    (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...

  14. Marshall Culpepper 2011-04-15

    (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...

  15. Taazza 2011-04-15

    @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.

  16. Taazza 2011-04-15

    @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.

  17. Thomas Huelbert 2011-04-15

    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.

JSON Source