+ All Categories
Home > Software > The Tale of a Smooth RecyclerView

The Tale of a Smooth RecyclerView

Date post: 07-Feb-2017
Category:
Upload: simek-adam
View: 85 times
Download: 0 times
Share this document with a friend
58
Transcript

The Tale of a Smooth RecyclerView

ADAM ŠIMEK

Knowing how to code lists is important

Kulman’s test

But why?

¯\_(ツ)_/¯

16

16ms

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

16ms?

Let’s get started

ListView

ListView

RecyclerView

RecyclerView Architecture

ViewHolder

ViewHolder

Best practice from ListViewLightweight view wrapper for list itemsRecycler holds a limited amount of them and reuses themOne ViewHolder is used for more items (not at a time)It has it’s own lifecyle

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) {}

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) {}

“The fastest code is the code that never runs.” Sokrates

What not to do?

Disk I/O - SQLite, SharedPreferences, Content Providersfor (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

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 placeholdersvoid onScrollStateChanged(…, int newState)

mHandler.postDelayed(deferredBind, DELAY }

☝ it’s crucial to keep this balanced

Test on various devices (low-end, tablets)…and with various dataStrictMode

Recycling saves our planet. Turns out it can save your app too.

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); } }); }

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 }

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

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); } }); }

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); } }); }

Measure twice, cut once.

AsyncTask

AsyncTask

Runs tasks in serial → super slowHm…executeOnExecutor(THREAD_POOL_EXECUTOR); Big operational overheadTricky and unreliable task cancelling

💥

java.util.concurrent.RejectedExecutionException: Task android.os.AsyncTask$3@36e83ee rejected from java.util.concurrent.ThreadPoolExecutor@a54e08f[Running, pool size = 13, active threads = 13, queued tasks = 128, completed tasks = 1055]

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 …

Sneaky things

Sneaky things

View.requestLayout() ——————— RecyclerView.setHasFixedSize( boolean hasFixedSize

) ——————— TextView.setAllCaps(boolean allCaps) ——————— notifyDatasetChanged()

View.requestLayout()

View.requestLayout() + hasFixedSize

void triggerUpdateProcessor() { if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) { ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable); } else { mAdapterUpdateDuringMeasure = true; requestLayout(); } }

Sneaky things

View.requestLayout() ——————— RecyclerView.setHasFixedSize( boolean hasFixedSize

) ——————— TextView.setAllCaps(boolean allCaps) ——————— notifyDatasetChanged()

TextView.setAllCaps()

public void setAllCaps(boolean allCaps) { if (allCaps) { setTransformationMethod(new AllCapsTransformationMethod(getContext())); } else { setTransformationMethod(null); } }

Sneaky things

View.requestLayout() ——————— RecyclerView.setHasFixedSize( boolean hasFixedSize

) ——————— TextView.setAllCaps(boolean allCaps) ——————— notifyDatasetChanged()

“Today I will do what others won't, so tomorrow I can accomplish what

others can’t"

Prefetch

Systrace

Systrace - missed frame

Prefetch OFF

Prefetch ON

Prefetch

Create and bind “up front”Estimates how long it will run to make sure it won’t cause delaysLollipop+ (RenderThread), support lib 25.1setItemPrefetchEnabled(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 👀

Thank you! @simekadam

strava.com/athletes/simekadam

@simekadam strava.com/athletes/simekadam


Recommended