在動畫正在播放的時候(如果你的動畫跟界面的座標點有關),界面失去隱藏,或者失去了焦點,如果沒有處理,就會報這個空指針異常。
復現場景:
自定義了一個父控件,然後裏面有一些子控件在執行動畫,動畫是根據屏幕的寬高移動,這時候,拉下Android的狀態欄,或者按home鍵,甚至退出程序,都會報一個空指針異常,異常如下圖。
java.lang.NullPointerException
at android.animation.KeyframeSet.getValue(KeyframeSet.java:183)
at android.animation.PropertyValuesHolder.calculateValue(PropertyValuesHolder.java:660)
at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1174)
at android.animation.ValueAnimator.animationFrame(ValueAnimator.java:1115)
at android.animation.ValueAnimator.doAnimationFrame(ValueAnimator.java:1144)
at android.animation.ValueAnimator$AnimationHandler.doAnimationFrame(ValueAnimator.java:623)
at android.animation.ValueAnimator$AnimationHandler.run(ValueAnimator.java:646)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:749)
at android.view.Choreographer.doCallbacks(Choreographer.java:562)
at android.view.Choreographer.doFrame(Choreographer.java:531)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:735)
at android.os.Handler.handleCallback(Handler.java:730)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:5103)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
at dalvik.system.NativeStart.main(Native Method)
解決:
從異常上
來看這個跟PropertyValuesHolder有關,但最終原因不確定。我是這麼想的,View Animation 底層的動畫執行過程依然跟Animator有關,所以在失去焦點後他便找不到座標點了,所以他的過渡點便成了null。只是這麼想,不知道對不對……
所以我在自定義控件的onVisibilityChanged()中,判斷了是否是顯示狀態,如果是顯示狀態,就讓他繼續播放動畫,否則我就執行動畫的cancel(),方法使之先取消。
cancel方法:取消動畫
【功能說明】該方法用於取消一個動畫的執行。該方法是取得一個正在執行中的動畫的主要方法。cancel方法和startNow方法結合可以實現對動畫執行過程的控制。需要注意的是,通過cancel方法取消的動畫,必須使用reset方法或者setAnimation方法重新設置,纔可以再次執行動畫。
@Override
protected void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
if (visibility != VISIBLE){
View childAt = getChildAt(XXX);
Animation animation = childAt.getAnimation();
animation.cancel();
}else{
View childAt = getChildAt(XXX);
childAt.getAnimation().reset();
childAt.getAnimation().start();
}
}