Android Webview performance optimization

1. Memory leak solution

Rewrite Webview and implement the following methods

 
 public MyWebView(Context context, AttributeSet attrs) {
        super(context, attrs, android.R.attr.webViewStyle);
        setBackgroundColor(Color.TRANSPARENT);
        // 删除掉Android默认注册的JS接口
        removeDefaultJavascriptInterface();
        WindowManager  wm= (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        setConfigCallback(wm);
   }
 
   @Override
    public void destroy() {
        getSettings().setJavaScriptEnabled(false);
        this.clearFormData();
        this.clearHistory();
        this.destoryWebView();
        super.destroy();
    }

    private void destoryWebView() {
        this.stopLoading();
        this.removeAllViews();
        if(this.getParent()!=null){
            //处理webview无法释放造成的内存泄漏,必须在destroy之前调用
            ViewGroup parent = (ViewGroup) this.getParent();
            parent.removeView(this);
            setConfigCallback(null);
        }

    }

    public void setConfigCallback(WindowManager windowManager) {
        try {
                if(Build.VERSION.SDK_INT>15) {
                    return;
                }
                Field field = WebView.class.getDeclaredField("mWebViewCore");
                field = field.getType().getDeclaredField("mBrowserFrame");
                field = field.getType().getDeclaredField("sConfigCallback");
                field.setAccessible(true);
                Object configCallback = field.get(null);
                if (null == configCallback) {
                    return;
                }
                field = field.getType().getDeclaredField("mWindowManager");
                field.setAccessible(true);
                field.set(configCallback, windowManager);
        } catch(Exception e) {
            e.printStackTrace();
            return;
        }
    }

refer to:

  • https://www.jianshu.com/p/eada9b652d99
  • https://blog.csdn.net/xygy8860/article/details/53334476?utm_source=itdadao&utm_medium=referral
  • https://stackoverflow.com/questions/11995270/error-webview-destroy-called-while-still-attached/12408703#12408703
  • https://www.jianshu.com/p/c2412918b2b5
  • org.chromium.android_webview.AwContents source code https://github.com/pwnall/chromeview/blob/master/src/org/chromium/android_webview/AwContents.java
  • https://chromium.googlesource.com/chromium/src/android_webview/glue/+/master/java/src/com/android/webview/chromium/WebViewContentsClientAdapter.java

 

2. SSL certificate processing

https://blog.csdn.net/zoeice/article/details/13996579

 

3. Handling common problems

The most complete WebView use in history, with a copy of Html5Activity

 

4.onPageFinished is called multiple times

Use onPageProgressChanged instead

private void  handleProgress(WebView view, int newProgress){
    if(progressPending.get()!=newProgress){
        progressPending.set(newProgress);
        onProgressChanged(newProgress);

    }
}
@Override
public final void onProgressChanged(WebView view, int newProgress) {
    super.onProgressChanged(view, newProgress);
    handleProgress(view,newProgress);
}

public void onProgressChanged(int newProgress){
   Log.i("WebChromeClient","progress="+newProgress+"%");
   if(newProgress==100){
       Log.i("WebChromeClient","Loading complete");
   }
}

5. The title returned by onReceiveTitle in the WebChromeClient interface is the url

The solution is as follows

@Override
public final void onReceivedTitle(WebView view, String title) {
    super.onReceivedTitle(view, title);
    handleProgress(view,view.getProgress());
    if(!TextUtils.isEmpty(title) && !TextUtils.isEmpty(view.getUrl())&& !view.getUrl().contains(title)){
        onReceivedTitle(title);
    }
}

public void onReceivedTitle( String title){

}

6. Using ApplicationContext

Using ApplicationContext can reduce the dependence on the current Activity and facilitate memory release, but there are still some problems to be dealt with, such as ApplicationContext cannot load themes, and must be loaded through ContextThemeWrapper. In addition, if WebChromeClient is not set when ApplicationContext is used, dialog boxes such as alert and confirm cannot be displayed.

The reason why it cannot be displayed can refer to the source code:

https://chromium.googlesource.com/chromium/src/android_webview/glue/+/master/java/src/com/android/webview/chromium/WebViewContentsClientAdapter.java

 private boolean showDefaultJsDialog(JsPromptResult res, int jsDialogType, String defaultValue,
            String message, String url) {
        如果Context不是一个Activity是不允许显示的
        Context activityContext = AwContents.activityFromContext(mContext);
        if (activityContext == null) {
            Log.w(TAG, "Unable to create JsDialog without an Activity");
            return false;
        }
        try {
            new JsDialogHelper(res, jsDialogType, defaultValue, message, url)
                    .showDialog(activityContext);
        } catch (WindowManager.BadTokenException e) {
            Log.w(TAG,
                    "Unable to create JsDialog. Has this WebView outlived the Activity it was created with?");
            return false;
        }
        return true;
    }

Inheritance Diagram

If the h5 page is not suitable for alert, confirm, etc., you can use ApplicationContext, otherwise it is recommended to use activitiy or set WebChromeClient to implement it yourself. Here is an example of using the ApplicaitonContext.

public MyWebView(Context context, AttributeSet attrs) {
    super(WebThemeContext.wrapper(context), attrs, android.R.attr.webViewStyle);
}
public class WebThemeContext extends ContextThemeWrapper {

    public WebThemeContext ( Context context) {
        super(MyApplication.getInstance(), context.getTheme()); //Set the theme
    }

    public static WebThemeContext wrapper( Context context){
        return new WebThemeContext(context);
    }
    @Override
    public Context getApplicationContext() {
        return getInstance.getInstance();
    }


}

 7. Performance Monitoring

https://blog.csdn.net/lmj623565791/article/details/58626355

8. Android WebView input box keyboard does not pop up

When overriding MyView, the theme id used must be set and set to android.R.attr.webViewStyle, otherwise native services such as keyboard cannot be called

9. Should Android Webview enable hardware acceleration?

Since there are too many fragmentation problems, it is recommended to keep the default state [the default means that it is determined by the system, do not set it manually], otherwise problems may occur.

 

10. Memory leak caused by cookie synchronization

When using CookieSyncManager to synchronize, the Context of the first acitivity will be permanently referenced. In order to avoid this situation, please use ApplicationContext

 if (Build.VERSION.SDK_INT < 21) {
        android.webkit.CookieSyncManager.createInstance(context.getApplicationContext());
}

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325068813&siteId=291194637