前期做音乐播放器有个需求是桌面有一个浮标里面有音乐封面,如果音乐在播放的时候封面图片要旋转,后面有发现只要我的浮标在并且图片旋转会导致activity的onDestory方法延时10秒回调。
百思不得其解,最后还是发现因为使用Animation动画在页面销毁的时候没有停止会出现这种情况。
最终解决方法:由于activity销毁动画还要继续,浮标是全局的,音乐播放是service在后台一直播放所以动画不能随activity生命周期结束,所以也不能停止Animation,最后换成属性动画ObjectAnimator
if(objectAnimator==null) {
objectAnimator = ObjectAnimator.ofFloat(
imageView, "rotation", 0f, 360f);
objectAnimator.setDuration(7000);
objectAnimator.setInterpolator(new LinearInterpolator());
objectAnimator.setRepeatCount(ValueAnimator.INFINITE);
}
objectAnimator.start();
这样结果是能正常的activity销毁回调onDestory方法。
分析一下原因:
在activity生命周期过程中新显示的Activity在resume后,App的主线程空闲下来才会通知AMS执行后续流程,将之前上一个关闭的Activity销毁。如果新显示Activity在resume后,主线程一直在循环处理MessageQueue中堆积的msg的话(Animation动画一直在post Runnable到主线程),通知AMS执行销毁上一个倍关闭的activity流程自然被延迟了ondestory方法回调也自然被延迟。但是android系统在resume之后还是有一个容错机制
//ActivityStack.java
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
.....
// From this point on, if something goes wrong there is no way
// to recover the activity.
try {
next.completeResumeLocked();
} catch (Exception e) {
// If any exception gets thrown, toss away this
// activity and try the next one.
Slog.w(TAG, "Exception thrown during resume of " + next, e);
requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null,
"resume-exception", true);
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
return true;
}
.....
}
//ActivityRecord.java
void completeResumeLocked() {
.....
// Schedule an idle timeout in case the app doesn't do it for us.
mStackSupervisor.scheduleIdleTimeoutLocked(this);
.....
//ActivityStackSupervisor.java
void scheduleIdleTimeoutLocked(ActivityRecord next) {
if (DEBUG_IDLE) Slog.d(TAG_IDLE,
"scheduleIdleTimeoutLocked: Callers=" + Debug.getCallers(4));
Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG, next);
mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);//延时10s处理以及销毁的activity
}
Animation.start():最终执行到
//Animation.java
private void fireAnimationStart() {
if (mListener != null) {
if (mListenerHandler == null) mListener.onAnimationStart(this);
else mListenerHandler.postAtFrontOfQueue(mOnStart);
}
}
往MessageQueue不断的发Runnable。
因此如果在Animation没有停止会导致activity的onDestory方法回调延时10秒执行。但是Animator则是最终会在 Choreographer中执行
// Thread local storage for the choreographer.
private static final ThreadLocal sThreadInstance =
new ThreadLocal() {
@Override
protected Choreographer initialValue() {
Looper looper = Looper.myLooper();
if (looper == null) {
throw new IllegalStateException("The current thread must have a looper!");
}
Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
if (looper == Looper.getMainLooper()) {
mMainInstance = choreographer;
}
return choreographer;
}
};
并不是主线程,因此不会影响activity的生命周期回调。
更多文章请关注公众号: