Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Fast List Scrolling with ORMLite

Fast List Scrolling with ORMLite

"Buttery-smooth" list scrolling is an important part of ensuring a good user experience on Android. But achieving this when rendering data from multiple database tables can be tricky. This talk will describe the steps I took to debug the performance issues and arrive at a solution using ORMLite.

Originally presented at Toronto Android Developers Meetup (http://www.meetup.com/ToAndroidDev/events/230143896/).

A key part of this slide deck are the animated screen captures, which are lost during the conversion to PDF. For the original slides, please go to Google Slides: https://docs.google.com/presentation/d/1L9nNONHQWAHVaC4Qwpu3sZ2yaXw1wnB6CX_rCch4mcM/edit?pref=2&pli=1#slide=id.g12a97b667f_0_291

Eric Fung

April 13, 2016
Tweet

More Decks by Eric Fung

Other Decks in Programming

Transcript

  1. Goal: Responsive UI List scrolling can be tricky Learn About

    CursorAdapter, ORMLite, Traceview, Deferred Updates, Section Headings From Problem to Solution Walkthrough of how I debugged
  2. INTRODUCTION ◦ Shopify helps entrepreneurs sell things ◦ App for

    merchants to manage their store’s orders and products
  3. Adapter ◦ Bridge between ListView and data ◦ Renders data

    into views REVIEW ORM ◦ Technique to access DB from OO language ◦ Classes instead of rows ◦ Updates are just setter calls
  4. EXISTING IMPLEMENTATION Photo by Sonja Langford ◦ Fetch rows, store

    into array ◦ Compute section headings ◦ ArrayAdapter ◦ S-L-O-W
  5. USE A CURSORADAPTER Seems obvious! ◦ Cursor is a DB

    control that lets you traverse results ◦ Fits with ListView and Adapter Why didn’t we use it? ◦ All rows needed to compute section headings
  6. USE A CURSORADAPTER ◦ ORMLite’s latest release (Dec 2013) doesn’t

    have it ◦ PR submitted mid-2014 based on https://github. com/campnic/ormlite-android- extras ◦ But not released… ◦ Build your own JAR or use JitPack
  7. ◦ Load time negligible ◦ But… content judders while scrolling

    ◦ UI thread can’t keep up ◦ Section headings lost USE A CURSORADAPTER
  8. “ The key to a smoothly scrolling ListView is to

    keep the application’s main thread … free from heavy processing. Ensure you do any disk access, network access, or SQL access in a separate thread. https://developer.android.com/training/improving- layouts/smooth-scrolling.html
  9. USE A CURSORADAPTER ◦ 60fps = <17ms per frame ◦

    Images loaded in background ✔ ◦ Database queries via CursorLoader ✔ ◦ What else is slowing down the UI thread? Photo by Bhavyesh Acharya
  10. METHOD PROFILING ◦ Android Device Monitor is a suite of

    tools for debugging and analysis: DDMS, OpenGL Tracer, HierarchyViewer, Systrace, Traceview ◦ Not to be confused with Android Monitor
  11. TRACEVIEW Logs method execution over time and shows execution data,

    per-thread timelines, and call stacks. Good for tracking down performance problems in your source code.
  12. HOW TO 1. Launch app 2. Start method profiling 3.

    Interact with app (fling list) 4. Stop profiling
  13. METHOD PROFILING ◦ There was a lot of activity on

    the main thread ◦ The profiling pane revealed these calls to be DB calls ◦ But why?
  14. ◦ Variants are a different version of a product ◦

    Merchants want to know if any products are low on inventory DATA MODEL
  15. @ForeignCollectionField(eager = false) private Collection<ProductVariant> variants; ORMLITE FOREIGN COLLECTIONS ◦

    Modelled in ORMLite through a ForeignCollection ◦ Define whether fetching model also fetches its foreign collections (eager vs. lazy)
  16. public int numberOfOutOfStockVariants() { int count = 0; for (ProductVariant

    variant : variants) { if (variant.isOutOfStock()) { count++; } } return count; } ORMLITE FOREIGN COLLECTIONS Can you spot the DB access?
  17. “ http://ormlite.com/javadoc/ormlite-core/doc- files/ormlite_2.html#Foreign-Collection …the collection is considered to be "lazy"

    and will iterate over the database using the Dao.iterator() only when a method is called on the collection.
  18. public int numberOfOutOfStockVariants() { int count = 0; for (ProductVariant

    variant : variants) { if (variant.isOutOfStock()) { count++; } } return count; } ORMLITE FOREIGN COLLECTIONS We’d like to keep this abstraction
  19. Don’t display all rows Paginate at bottom Return join of

    tables Joined result set not supported in ORMLite Denormalize Put inventory in product, maintain integrity ALTERNATIVES
  20. 1. When product is rendered, queue fetch of variants 2.

    Track which view needs updating 3. Fetch variants in background 4. When data is available, compute inventory 5. Update the view IDEA
  21. 1. Adapter puts entry into shared structure, mapping product to

    view 2. Adapter sends message to worker to fetch variants 3. Worker processes messages in FIFO order 4. Fetches variant and computes inventory 5. Removes entry from data structure, updates view IMPLEMENTATION
  22. ◦ Why do we care? ▫ It’s in the designs

    ▫ It allows you to enable fast scrolling ◦ Built-in AlphabetIndexer was way too slow ƌ ◦ Various blog posts about CursorAdapter + SectionIndexer ƌ SECTION HEADINGS
  23. Section A group of list items with something in common,

    e.g. first letter of title, album artist SECTIONINDEXER Indices ◦ Given index of section, return adapter position ◦ Given adapter position, return section it belongs to
  24. If we knew the count of items in each group

    of products that start with the same letter, we could easily calculate the section indices Hint hint! SECTIONINDEXER
  25. SELECT SUBSTR(UPPER(title),1,1) AS section, COUNT(*) FROM `products` GROUP BY section

    ORDER BY section A|125 B|123 C|153 D|69 … GENERATE SECTION INDICES WITH SQL
  26. ◦ Executes fast ◦ Pre-compute and pass to Adapter ◦

    Define a wrapping list adapter on top of CursorAdapter GENERATING SECTION INDICES WITH SQL
  27. CONCLUSION ◦ Smooth list scrolling is essential for good UX

    ◦ Use CursorAdapter with DB data to back your ListView ◦ Profile your app to find hot spots ◦ Defer updating views if needed ◦ Sometimes SQL > Java