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

Tale of a Smooth RecyclerView

Avatar for simekadam simekadam
January 26, 2017

Tale of a Smooth RecyclerView

Tips and tricks how to make you lists perform well

Avatar for simekadam

simekadam

January 26, 2017

Other Decks in Programming

Transcript

  1. 16

  2. “Well, that’s: user input, networking, data processing, database/disk I/O, view

    inflation, layout, drawing,… Thwre also other applications, cpus are slow, memories are too, everything takes forever. And then you are supposed to save battery.”
  3. ViewHolder Best practice from ListView Lightweight view wrapper for list

    items Recycler holds a limited amount of them and reuses them One ViewHolder is used for more items (not at a time) It has it’s own lifecyle
  4. ViewHolder Lifecycle @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {}

    @Override public void onBindViewHolder(ViewHolder holder, int position) {} @Override public void onViewAttachedToWindow(ViewHolder holder) {} @Override public void onViewDetachedFromWindow(ViewHolder holder) {} @Override public void onViewRecycled(ViewHolder holder) {} @Override public boolean onFailedToRecycleView(ViewHolder holder) {}
  5. ViewHolder Lifecycle @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {}

    @Override public void onBindViewHolder(ViewHolder holder, int position) {} @Override public void onViewAttachedToWindow(ViewHolder holder) {} @Override public void onViewDetachedFromWindow(ViewHolder holder) {} @Override public void onViewRecycled(ViewHolder holder) {} @Override public boolean onFailedToRecycleView(ViewHolder holder) {}
  6. What not to do? Disk I/O - SQLite, SharedPreferences, Content

    Providers for (Comment comment : item.getComments()) {} Parsing of text, JSONu,…, complicated formatting,.. Html.fromHtml() Complicated layouts “I can go home, it’s runs smooth on my phone.” Critical code can be hidden (deep) in the abstraction
  7. What to do? Everything expensive has to run in background

    …,or it has to be preprocessed You don’t have to show it right away → use tmp placeholders void onScrollStateChanged(…, int newState) mHandler.postDelayed(deferredBind, DELAY } ☝ it’s crucial to keep this balanced Test on various devices (low-end, tablets) …and with various data StrictMode
  8. Guess what’s wrong? //ViewHolder code called in onBindViewHolder() @Override public

    void bindData(Object data, final int position) { mImageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mClickHandler.onItemClicked(v, position, photo); } }); }
  9. Guess what’s wrong? //ViewHolder code called in onBindViewHolder() @Override public

    void bindData(Object data, final int position) { mImageView.setOnClickListener(mClickListener); // use member var instead }
  10. Guess what’s wrong? //ViewHolder code called in onBindViewHolder() @Override public

    void bindData(Object data, final int position, ItemClickListener listener) { mImageView.setOnClickListener(listener); // even better.. }
  11. Guess what’s wrong? //ViewHolder code called in onBindViewHolder() @Override public

    void bindData(Object data, final int position) { mImageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mClickHandler.onItemClicked(v, position, photo); } }); }
  12. Guess what’s wrong? //ViewHolder code called in onBindViewHolder() @Override public

    void bindData(Object data, final int position) { mImageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mClickHandler.onItemClicked(v, getAdapterPosition(), photo); } }); }
  13. AsyncTask Runs tasks in serial → super slow Hm… executeOnExecutor(THREAD_POOL_EXECUTOR);

    Big operational overhead Tricky and unreliable task cancelling
  14. DIY Custom “taskmanager” … mDecodeThreadPool = new ThreadPoolExecutor( NUMBER_OF_CORES, //

    Initial pool size NUMBER_OF_CORES, // Max pool size KEEP_ALIVE_TIME, KEEP_ALIVE_TIME_UNIT, mDecodeWorkQueue); // 128 size in AsyncTask … mDecodeThreadPool.execute(DownloadTask); // execute task …
  15. View.requestLayout() + hasFixedSize void triggerUpdateProcessor() { if (POST_UPDATES_ON_ANIMATION && mHasFixedSize

    && mIsAttached) { ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable); } else { mAdapterUpdateDuringMeasure = true; requestLayout(); } }
  16. TextView.setAllCaps() public void setAllCaps(boolean allCaps) { if (allCaps) { setTransformationMethod(new

    AllCapsTransformationMethod(getContext())); } else { setTransformationMethod(null); } }
  17. “Today I will do what others won't, so tomorrow I

    can accomplish what others can’t"
  18. Prefetch Create and bind “up front” Estimates how long it

    will run to make sure it won’t cause delays Lollipop+ (RenderThread), support lib 25.1 setItemPrefetchEnabled(true) Supported by built-in LayoutManageres (API for custom ones) Watch out for onBindViewHolder - no animations,… setInitialPrefetchItemCount(N) You can see the difference with your naked eye