Android效能優化(1)—webview優化篇

孫博文啊發表於2018-03-12

寫這篇文章的主要是因為在實際應用的時候遇到了很多棘手的問題(文章最後部分,交流一下遇到的問題),在這裡分享出來讓人少走一些彎路,如果有不對的地方直接留言即可

相信一般做Android開發的同學都會或多或少的使用webview,(由於不太瞭解js,js互動的部分暫時沒有)相信有不少人的使用過程是這樣的

佈局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </WebView>
</LinearLayout>

使用

    //設定webview
    WebSettings websettings = webView.getSettings();
    websettings.setJavaScriptEnabled(true);
    websettings.setDomStorageEnabled(true);
    websettings.setJavaScriptCanOpenWindowsAutomatically(true);
    websettings.setBuiltInZoomControls(false);// 
    webView.loadUrl(url);

上邊這樣使用,在使用量少的情況下可能沒有問題,但是也給程式留下了不少隱患–記憶體洩漏,由於webview並沒有完全清除掉,一直持有對應的上下文,導致記憶體無法被回收

說道這裡就有了第一種的優化

優化一

既然說沒有主動回收,那我們就手動回收在,activity的onDestroy方法中清除webview

public void onDestroy() {
    super.onDestroy();
    webView.clearHistory();
    webView.clearView();
    webView.removeAllViews();
    webView.destroy();
}

當你做完這些操作後,退出當前的activity,發現記憶體好像並沒有減少(或者浮動不大)原因請參考
http://blog.csdn.net/u013085697/article/details/53259116

優化二

在需要用到webview的地方直接new一個出來,而不是在.xml檔案中定義webview

佈局

在佈局需要使用webview的地方使用一個FrameLayout代替(其他的容器也可以)

使用
/**
*建立webview並新增到佈局容器中
*/
public void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   WebView webView = WebviewUtil.createNewWebView(context);
   FrameLayout frameLayout  = findViewById(R.id.xxx);
   frameLayout.addView(mWebView);
}
...
/**
*建立webview公共方法
*/
public static android.webkit.WebView createNewWebView(Context context){
    android.webkit.WebView webView = new android.webkit.WebView(context.getApplicationContext());
    webView.setLayerType(View.LAYER_TYPE_SOFTWARE, new Paint());
    webView.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT));
    return webView;
}

/**
*清除webview
*/
public void onDestroy() {
 if (null != webView) {
        try {
            webView.removeJavascriptInterface("xx");
            webView.getSettings().setJavaScriptEnabled(false);
            webView.loadUrl("about:blank");
            webView.loadDataWithBaseURL(null, "", "text/html", "uft-8", null);
            ViewParent parent = webView.getParent();
            if (parent != null) {
                ((ViewGroup) parent).removeView(webView);
            }
            webView.clearHistory();
            webView.clearView();
            webView.removeAllViews();
            webView.destroy();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    super.onDestroy();
   
}

但是通過以上操作,檢視記憶體並沒有被回收………

優化三 — 開程式

當你的webview需要的記憶體很大,但是主程式申請不到更多的記憶體的情況下可以使用。

此方法各大主流APP基本都是這樣操作的,在開啟webview頁面後,檢視此應用的程式是否多開了一個。

開程式的方法也很簡單隻需要在你需要的activity在AndroidManifest中註冊的時候新增“process”屬性即可,但是注意程式間的通訊;當關閉此activity時殺掉此程式不然記憶體不能被回收,下次進入時記憶體累加,最終會導致溢位

    <activity
        android:name=".Activity"
        android:process=":remoteView"
       />

如果開啟程式的速度慢可以先進行程式的預載入,先啟動一個和上邊activity同一個程式的service,然後再開啟activity

優化四–使用第三方

騰訊的x5核心,具體的優勢可以參考騰訊官方文件

最後,再來說說我遇到的問題吧,首先需求是這樣的一個頁面需要多個統計圖(百度的echarts,為了保持兩端一致性和多樣化的圖表需求)每一個圖表都需要一個對應的webview

沒辦法,產品提出來了

1開始使用第一種,崩潰,卡頓問題不斷

2使用方法二,解決了大部分的機型,只有藍綠大廠不行(吐槽中OPPO、vivo)
會出現無故的崩潰,檢視logo日誌(包括sdk底層logo日誌)都只能找到一個記憶體地址的錯誤,比如:

Fatal signal 11 (SIGSEGV), code 1, fault addr 0x9ffffffff in tid 30218 (Thread-708)

沒有其他任何提示,騰訊的bugly,友盟也沒有抓取到相關的資訊,崩潰中
後來查到兩點問題

1、echarts的問題,其中有一個svg渲染(官方是beta版),是為了給低效能裝置使用,看情況使用,有些圖表會出現點選藍屏閃爍(只是在webview範圍之內),不過親測記憶體降低了太多,沒有使用前一個帶滑塊的圖表達到了快200M,改為svg之後一直維持在30+M,提升明顯,如果使用請自行測試多種機型

2、還是echarts 的問題,資料返回後多次向webview傳入了資料導致崩潰,改為一次後暫未發現

以上兩個問題目前只在OPPO和vivo手機發現,希望有此需求的小夥伴注意此問題


相關文章