Activity onDestroy方法未能及時執行原因
網上出現的情況也不少,大致看了下主要有以下幾類:
- AndroidManifest 針對某個activity 設定的theme為 @android:style/Theme.NoTitleBar
在目前專案中(android2.0),發現一個嚴重BUG。當打開了A,B兩個頁面的時候,此時當前頁面為B,如果在B中呼叫finish()後,雖然已經回到了A,但B卻並沒有執行onDestroy()方法,只有在手機上按動了某一個按鍵後,這時才會執行B.onDestroy()。B才會完全銷燬。另:如果按手機自帶的返回按鈕,卻不會出現這種情況。
因此,如果此時在onDestroy()方法有一些操作的話,那麼在回到A不進行按鍵操作的話,B並沒有及時銷燬,所以不會做方法中的這些操作。
經定位修改後發現,此BUG是由於在AndroidManifest.xml中對A頁面設定了android:theme="@android:style/Theme.NoTitleBar"。而B頁面並沒有設定此引數造成的。把B增加此設定後,問題解決。
雖然問題已解決,但一直沒有明白未設定android:theme="@android:style/Theme.NoTitleBar"的頁面,為什麼會在finish()後不能馬上呼叫onDestroy()。按理說兩者不應該有什麼關聯才是。
我寫了一個Activity,反覆進去和退出,這樣重複20次,TV的記憶體居然從53M升到了驚人的 170M,
- Activity 的 onDestroy() 是系統回撥函式, 呼叫時機是不確定的
據張明雲(程式設計,Andoid開發話題的優秀回答者)所說,在finish()方法之後沒有立即執行onDestroy()方法,只是上述這個命題的一種情況,不僅如此,Activity的其他生民週期方法何時會呼叫也是不確定的,onDestroy沒有及時執行暫未找到有效的處理方法,但可以通過isFinishing()方法判斷 Activity 是否處於銷燬狀態。
- 按下home,再在recent中強行刪除
這種情況據網上回答,位於棧頂的Activity是會執行onDestroy(),棧內其他Activity不會執行。據我測試,一個都沒執行。因為又有回答說 Activity被手機記憶體強制回收是不會呼叫destory方法的。
- onDestroy() 和 finish()
finish()方法用於結束一個Activity的生命週期,而onDestory()方法則是Activity的一個生命週期方法,其作用是在一個Activity物件被銷燬之前,Android系統會呼叫該方法,用於釋放此Activity之前所佔用的資源。
finish會呼叫到onDestroy方法,
可以在onDestroy裡列印一句話,就會發現在finish方法那也會列印這句話。。。
Activity.finish()
Call this when your activity is done and should be closed.
在你的activity動作完成的時候,或者Activity需要關閉的時候,呼叫此方法。
當你呼叫此方法的時候,系統只是將最上面的Activity移出了棧,並沒有及時的呼叫onDestory()方法,其佔用的資源也沒有被及時釋放。因為移出了棧,所以當你點選手機上面的“back”按鍵的時候,也不會再找到這個Activity。
Activity.onDestory()
the system is temporarily destroying this instance of the activity to save space.
系統銷燬了這個Activity的例項在記憶體中佔據的空間。
在Activity的生命週期中,onDestory()方法是他生命的最後一步,資源空間等就被回收了。當重新進入此Activity的時候,必須重新建立,執行onCreate()方法。
- 我遇到的情況
在發現問題原因之前進行了多方面排查,主要有
- activity呼叫finish卻不立即執行onDestroy
- SignFragment中實現定位?
- intent.setClass()?
- xml中 tools:context?
- Androidmanifest中具體的activity的屬性 configuration?
- 專案activity達到峰值了?
- v4 Fragment 還是 Fragment?
經過2/3的工作日時間找到了問題出處,雖然找到了問題,可是處理起來還是比較費勁。
我的情況是在Fragment中使用了下面程式碼,然後跳轉到Activity,退出Activity時,Activity 的 onDestroy()方法延遲了幾秒執行。
animation = AnimationUtils.loadAnimation(mContext, R.anim.anim_sign_in);
@Override
public void onResume() {
super.onResume();
EventBus.getDefault().register(this);
mAnim.startAnimation(animation);
}
@Override
public void onPause() {
super.onPause();
EventBus.getDefault().unregister(this);
mAnim.setAnimation(null);
}
移除這句話的時候,Activity 的onDestroy()方法會立即執行。
mAnim.startAnimation(animation);
首先將startAnimation()改為 setAnimation(),在onPause()中在置null,發現還是一樣。其次研究了一下AnimationUtils的基本使用情況,設定以下程式碼,效果還是一樣
@Override
public void onResume() {
super.onResume();
EventBus.getDefault().register(this);
mAnim.setAnimation(animation);
animation.startNow();
}
@Override
public void onPause() {
super.onPause();
EventBus.getDefault().unregister(this);
animation.cancel();
mAnim.setAnimation(null);
}
將Animation 改用Animator 試試看,以我的理解是 Animation應該要被棄用了,它能實現的,Animator都能實現,並且更遵循面向物件的原則。所以改為以下方式後在執行,發現 Activity的onDestroy() 方法會隨著Activity 介面消失立即執行。
private void test() {
ObjectAnimator anim1 = ObjectAnimator.ofFloat(mAnim,"scaleX",1.2f,0.8f);
anim1.setRepeatCount(-1);
ObjectAnimator anim2 = ObjectAnimator.ofFloat(mAnim,"scaleY",1.2f,0.8f);
anim2.setRepeatCount(-1);
AnimatorSet set = new AnimatorSet();
set.play(anim1).with(anim2);
set.setDuration(1000);
set.start();
}
private void startAnimator() {
Animator anim = AnimatorInflater.loadAnimator(mContext,R.animator.anim_signnal);
anim.setTarget(mAnim);
anim.start();
}
問題總算是解決了,不過伴隨著的知識還是有很多地方需要去了解和加深的。