Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android5.1系統WebView內存洩漏場景

Android5.1系統WebView內存洩漏場景

編輯:關於Android編程

問題現象

(該文章,引自零號路的私人博客,本人在浏覽框架的開發過程中,用該方式,規避了內存洩露的問題。)

在Android5.1系統中,會發現App存在 WebView 洩漏情況,還比較嚴重。並且只是發生在 Android 5.1 系統。

GC roots 如下:

\

每新打開一次這個WebViewActivity,就會發生就會發生一次改Webview實例無法釋放,新增一個對象。

上圖中的兩個 AppSearchWebView實例,就是由於打開了兩次導致。

問題分析

出現了這個問題分析起來還是比較簡單的,根據這個引用關系,我們可以直觀的看到是由於 Appsearch(extends Application)的 mComponentCallbacks 一直在強引用AWComponentCallbacks,導致無法釋放。然後AWComponentCallbacks -> AWContents > AppSearchWebView。

通過分析代碼發現關鍵在於 AwContents 這裡的 AwComponentsCallbacks 為什麼沒有釋放。

    @Override
    public void onAttachedToWindow() {
        if (isDestroyed()) return;
        if (mIsAttachedToWindow) {
            Log.w(TAG, "onAttachedToWindow called when already attached. Ignoring");
            return;
        }

		......

        mComponentCallbacks = new AwComponentCallbacks();
        mContext.registerComponentCallbacks(mComponentCallbacks);
    }

    @Override
    public void onDetachedFromWindow() {
        if (isDestroyed()) return;
        if (!mIsAttachedToWindow) {
            Log.w(TAG, "onDetachedFromWindow called when already detached. Ignoring");
            return;
        }
		......

        if (mComponentCallbacks != null) {
            mContext.unregisterComponentCallbacks(mComponentCallbacks);
            mComponentCallbacks = null;
        }

		......
    } 

看這段代碼看不出來什麼問題,onAttach的時候 register,detach的時候 unregister, 不會存在問題。

但是為什麼呢?

難道是由於 if (isDestroyed()) return 這條return引起的?

當調用 Webview.destroy() 後 這個判斷 返回true。

我們看下哪裡調用了 webview.destroy()

// source from WebViewActivity

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

很多應用應該都是這麼做的,包括系統浏覽器,在Activity destroy的時候,調用 webview的destroy。並且一直工作的很好。

通過調試發現,確實是由於此調用導致的。onDestroy 發生在 onDetach 之前。

那為什麼 android 5.1 之前的代碼沒有問題呢?

看下代碼:

	// AwContents.java

    @Override
    public void onDetachedFromWindow() {
        if (!mIsAttachedToWindow) {
            Log.w(TAG, "onDetachedFromWindow called when already detached. Ignoring");
            return;
        }
		
		......

        if (mComponentCallbacks != null) {
            mContext.unregisterComponentCallbacks(mComponentCallbacks);
            mComponentCallbacks = null;
        }
		......
	}

相對於 5.1 的代碼少了那句if (isDestroyed()) return;

規避方法

    解決方案可以:在destroy之前,把webview 從 parent 中 remove 掉,同樣可以提前detach。

      protected void onDestroy() {
          if (mWebView != null) {
              ((ViewGroup) mWebView.getParent()).removeView(mWebView);
              mWebView.destroy();
              mWebView = null;
          }
          super.onDestroy();
      }
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved