Android開發 在Activity里釋放資源的一種思維


前言

  當前你已經入門Android開發,開始關注深入的問題,你就會碰到一個Android開發階段經常碰到的問題,那就是內存泄漏. 其實大多數Android的內存泄漏都是因為activity里的資源釋放不正確導致,activity與單例或者接口互相持有無法釋放.這篇博客就來講解如何在Android里最優的釋放資源.

  請注意,此篇博客只是一個思維參考,請不要將全部activity的資源釋放都套用這個方式,其實釋放資源與初始化資源最好的方式是深刻理解Activity的生命周期,來決定何時初始化資源何時釋放資源!

錯誤釋放資源的一些例子

  在看正面例子之前,我們看看反面例子,了解為什么經常莫名其妙的內存泄露

在Activity的onDestroy()的生命周期里釋放資源

在下面的onDestroy()方法里我們有一個叫mHttpList的資源要釋放,我們都知道activity的生命周期的最后是onDestroy方法,那么為什么在onDestroy()里釋放資源會有問題呢?

  問題出在onDestroy()生命周期並不是立即執行的.Activity退出前台后先是進入棧里的.是否執行onDestroy()是交給系統決定的,一般情況下系統的確會及時的運行onDestroy()方法銷毀activity,但是在一些Activity跳轉頻繁的情況下可能系統並不會馬上運行onDestroy()方法.這個時候問題就出現了你認為應該結束的資源並沒有馬上結束可能導致一些回調報錯或者內存泄露.

  @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mHttpList != null){
            mHttpList.release();
            mHttpList = null;
        }
        
    }

在Activity的finish()方法里釋放資源

同上環境,那么finish方法里釋放資源有那些問題呢?

  重寫的finish()是一個釋放資源的好地方,在按返回鍵(或者你自己主動調用onBackPressed()方法)和主動調用finish()方法時,重寫的finish()都是會運行的.但是在這個方法在有一種情況下是不運行的,就是在后台太久后的自動清理或者其他Activity的啟動模式是android:launchMode="singleTask"  在其他activity的singleTask下會自動清理它棧前的所以Activity,在這種情況下如果你的activity要被清理掉finish()方法是不會運行的.這樣你的資源就沒有被釋放了.

    @Override
    public void finish() {
        super.finish();
        if (mHttpList != null){
            mHttpList.release();
            mHttpList = null;
        }
    }

在Activity的onPause()和onStop()里釋放資源

onPause()和onStop()我們都知道activity后台的時候會調用這2個生命周期先onPause() 然后在 onStop(),如果是Dialog模式的Activity彈出只會進入onPause(). 他們的問題是什么呢?

  問題是如果在操作太快的操作前后台,就會導致我們的資源需要頻繁的在onRestart()或者onResume() 重新初始化或者注冊.這是較好的一種釋放資源的方式一般情況下是推薦這種的,但是快速頻繁的操作初始化與釋放是最容易出現內存泄漏的...特別是初始化如果是耗時的...

@Override
    protected void onPause() {
        super.onPause();
        Log.e(TAG, "onPause: ");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.e(TAG, "onStop: ");
    }

Activity里釋放資源的方式一

   onPause()或者onStop()結合onDestroy(),調用isFinishing()在方法判斷后釋放資源,如下代碼:    

    private boolean mIsRelease = false;

    /**
     * 釋放資源
     */
    private void release(){
        if (mIsRelease){
            return;
        }
        if (isFinishing()) {
            if (mHttpList != null) {
                mHttpList.release();
                mHttpList = null;
            }
        }
        mIsRelease = true;
    }

    @Override
    protected void onPause() {
        super.onPause();
        //結合實際情況也可以在onPause方法里 釋放資源,但是這里釋放資源有一個問題你需要知道並且避免:
     //在onPause生命周期執行的瞬間,activity其實是還在前台的,所以有概率出現資源已經被釋放,但是activity里的View是還有被點擊的機會導致空指針報錯(特別是在跑monkey的時候,容易出現這種報錯)
} @Override
protected void onStop() { super.onStop();
     release();
} @Override protected void onDestroy() { super.onDestroy(); release(); }

  注意添加判空或者也可以在方法里套一個全局布爾值來判斷是否釋放過資源,防止重復釋放資源...  這里為什么onDestroy()還要運行一次?下面會說明原因.

  首先講講isFinishing()的作用就是判斷這個activity是不是需要被銷毀,還是只是進入后台.我驗證過以下情況:

1.在主動調用finish()方法的情況下,isFinishing() 返回的是true

2.在主動調用onBackPressed()方法或者按返回鍵的情況下, isFinishing() 返回的是true

3.如果只是因為進入到其他Activity而退到后台, isFinishing() 返回的是false

注意點:

1.完全依靠isFinishing()來決定釋放資源並不完美,還有一種情況可以跳過清理的,那就是SingleTask模式下這個Activity要被銷毀,但是后台因為入棧(入深棧最少在第三層的那種情況)已經觸發過onPause或者onStop,所以SingleTask的清理就跳過了isFinishing()判斷,直接走到了onDestroy().所以,我們需要在onDestroy()再次兜底,保證不會因為SingleTask的原因沒有釋放資源.

2.在onPause里釋放資源需要慎重,在onPause生命周期執行的瞬間,activity其實是還在前台的,所以有概率出現資源已經被釋放,但是activity里的View是還有被點擊的機會導致空指針報錯(特別是在跑monkey的時候,容易出現這種報錯)。

最后總結,以上這種釋放資源的組合,目的是在Activity真的要被銷毀的時候能盡快的釋放資源,又可以防止Activity只是在后台時需要重復注冊資源,最后依靠onDestroy()兜底保證資源不會因為SingleTask原因沒有釋放

 

 

End


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM