I realize, if I apply android:stateListAnimator
on RecylerView
's item, calling adapter.notifyDataSetChanged
will cause undesired flickering effect on certain RecylerView
's items (Not all items, strangely)
Here's my RecylerView's item
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
...
android:stateListAnimator="@anim/lift_up"
android:background="@drawable/white" >
...
</LinearLayout>
@anim/lift_up
is defined as
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_enabled="true"
android:state_pressed="true">
<objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="translationZ"
android:valueTo="8dip"
android:valueType="floatType" />
</item>
<item>
<objectAnimator
android:duration="@android:integer/config_shortAnimTime"
android:propertyName="translationZ"
android:valueTo="4dip"
android:valueType="floatType" />
</item>
</selector>
and @drawable/white
is defined as
<drawable name="white">#ffffffff</drawable>
When I call adapter.notifyDataSetChanged
, the following strange flickering effect happens at the last 5 items of RecylerView. (There are total 10 visible items on screen)
https://youtu.be/yB4UP2wEFk0
This problem only happen at API 21 and above, because only API 21 supports android:stateListAnimator
Is this a bug, or I had missed out something?
The complete minimal workable code can be downloaded from https://github.com/yccheok/RecyclerViewTutorial/tree/4763879598864233a8e6544fe240c3fb34a15b73
Not all items, strangely
This is by design (I believe).
Internally, all recycling ViewGroups (that I have dealt with) maintain a View pool. Its expensive to create a View from scratch. Some of this cost is dissipated by using a View pool, at the expense of resource usage. Size of this pool represents this tradeoff. A basic implementation can be looked at here: ViewPool from DeckView.
RecyclerView
does the same with RecycledViewPool. Note the default max size:
public static class RecycledViewPool {
....
private static final int DEFAULT_MAX_SCRAP = 5;
....
}
I believe the first 5 views in your case don't flicker because they come from the pool - they're not created when notifyDataSetChanged()
call is made. This might be the reason that the StateListAnimator
does not kick in. For the rest 5 rows/items, new Views are created.
From the source code:
View getViewForPosition(int position, boolean dryRun) {
....
// 0) If there is a changed scrap, try to find from there
....
// 1) Find from scrap by position
....
// 2) Find from scrap via stable ids, if exists
....
// fallback to recycler
....
// getRecycledViewPool() returns an instance of RecycledViewPool
holder = getRecycledViewPool().getRecycledView(type);
....
// if holder is still 'null' after checking the pool, create a new one
....
if (holder == null) {
holder = mAdapter.createViewHolder(RecyclerView.this, type);
}
....
}
As you can tell, recycling is a serious business. What I cannot explain is why options 0, 1, and 2
fail - or tell if they even do. To check my hypothesis, you can change the pool's max
size and note any difference(s) (in the # of views that flicker):
mRecyclerView
.getRecycledViewPool()
.setMaxRecycledViews(RecyclerView.INVALID_TYPE, 10);
If you check documentation of recyclerview method notifyDataSetChanged in http://androidxref.com/6.0.0_r1/xref/frameworks/support/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java for method notifyDatasetChanged, it mentions following "
RecyclerView
will attempt to synthesize visible structural change events
for adapters that report that they have {@link #hasStableIds() stable IDs} when
this method is used. This can help for the purposes of animation and visual
object persistence but individual item views will still need to be rebound
and relaid out.
Similar idea is sketched out also in https://www.youtube.com/watch?v=8MIfSxgsHIs where you would do stableIds true if you had to do animations for list view, also more examples in the above mentioned dev bytes series assume stable ids for animation persistence in list items.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With