记录一个遇到的问题
使用Lottie优雅的实现矢量动画,用起来妙啊,能够做到普通帧动画无法做到的功能,模仿的腾讯视频底部切换的动画.但是使用中发现了下图的问题.
我在这里点了快速运行,导致本身四个不同的图片变成和最后一个图片一样的了.,其实旋转屏也可以复现!
然鹅,如果出现这个问题的时候是旋转屏,我会直接晓得是场景恢复导致的,但是我发现的时候是快速运行和崩溃的时候复现的,我没有联想到,所以我找了好久.
那么问题已经找到了就是场景恢复导致的,那就去定位问题吧.
lottie 源码版本
implementation 'com.airbnb.android:lottie:2.7.0'
既然大致知道是场景恢复引发的这个事件,那么就直接查LottieAnimationView的这两个方法
- onSaveInstanceState
- onRestoreInstanceState
看了一下LottieAnimationView果然重写了这两个方法
onSaveInstanceState,果然保存了动画的属性,o(╥﹏╥)o
@Override protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
SavedState ss = new SavedState(superState);
ss.animationName = animationName;
ss.animationResId = animationResId;
ss.progress = lottieDrawable.getProgress();
ss.isAnimating = lottieDrawable.isAnimating();
ss.imageAssetsFolder = lottieDrawable.getImageAssetsFolder();
ss.repeatMode = lottieDrawable.getRepeatMode();
ss.repeatCount = lottieDrawable.getRepeatCount();
return ss;
}
onRestoreInstanceState 恢复的时候把对应的动画属性恢复过来了
@Override protected void onRestoreInstanceState(Parcelable state) {
if (!(state instanceof SavedState)) {
super.onRestoreInstanceState(state);
return;
}
SavedState ss = (SavedState) state;
super.onRestoreInstanceState(ss.getSuperState());
animationName = ss.animationName;
if (!TextUtils.isEmpty(animationName)) {
setAnimation(animationName);
}
animationResId = ss.animationResId;
if (animationResId != 0) {
setAnimation(animationResId);
}
setProgress(ss.progress);
if (ss.isAnimating) {
playAnimation();
}
lottieDrawable.setImagesAssetsFolder(ss.imageAssetsFolder);
setRepeatMode(ss.repeatMode);
setRepeatCount(ss.repeatCount);
}
你会说没毛病呀,一个对象一个资源,不会导致4个对象使用一个资源呀!这里先把原因说出来.
这四个LottieAnimationView有相同的id.
给你看个布局 R.layout.view_maintab,
//...省略
public class MainTab extends FrameLayout {
public MainTab(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
LayoutInflater.from(context).inflate(R.layout.view_maintab,
this);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MainTab);
String titleContent = typedArray.getString(R.styleable.MainTab_text);
Drawable drawable = typedArray.getDrawable(R.styleable.MainTab_img_res);
typedArray.recycle();
自定义了一个FrameLayout用来装布局,然后写一些共同的属性,来实现切换的tab!
问题原因:
这里因为场景恢复的数据通过onSaveInstanceState()先存到一个SparseArray
protected void dispatchRestoreInstanceState(SparseArray container) {
if (mID != NO_ID) {
//注意看这里
Parcelable state = container.get(mID);
if (state != null) {
mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
onRestoreInstanceState(state);
//....
}
}
}
在执行onSaveInstanceState()的时候最后一个tab因为id和前面的三个一致,直接覆盖了前面的数据.这就是问题的原因,那怎么办呢?
解决方式:
不写id了就好了呗!那你怎么获取对象呢?可以使用getChild()....等方式拿到对象.