2019独角兽企业重金招聘Python工程师标准>>>
1、内存泄漏解决方法
复写Webview,实现如下方法
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;
}
}
参考:
- 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源码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证书处理
https://blog.csdn.net/zoeice/article/details/13996579
3、常见问题处理
史上最全WebView使用,附送Html5Activity一份
4.onPageFinished被调用多次
使用onPageProgressChanged代替
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","加载完成"); } }
5.WebChromeClient接口中onReceiveTitle返回的标题是url
解决方法如下
@Override public final void onReceivedTitle(WebView view, String title) { super.onReceivedTitle(view, title); handleProgress(view,view.getProgress()); if(URLUtils.isNetworkUrl(title)){ return; } if(!TextUtils.isEmpty(title) && !TextUtils.isEmpty(view.getUrl())&& !view.getUrl().contains(title)){ onReceivedTitle(title); } } public void onReceivedTitle( String title){ }
6.使用ApplicationContext
使用ApplicationContext可以减少对当前Activity的依赖,便于内存释放,但是这里还有一些问题需要处理,比如ApplicationContext不能加载主题,必须通过ContextThemeWrapper加载。此外,如果使用了ApplicationContext时没有设置WebChromeClient的情况下,alert,confirm等对话框无法显示。
无法显示的原因可以参考源码:
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;
}
继承关系图
如果h5页面不适用alert,confirm等,可以使用ApplicationContext,否则建议使用activitiy或者设置WebChromeClient自行实现。这里提供一个使用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()); //设置主题 } public static WebThemeContext wrapper( Context context){ return new WebThemeContext(context); } @Override public Context getApplicationContext() { return getInstance.getInstance(); } }
7.性能监控
https://blog.csdn.net/lmj623565791/article/details/58626355
8.Android WebView 输入框键盘不弹出
在复写MyView时,使用的主题id必须设置,并且设置为android.R.attr.webViewStyle,否则无法调用native服务,如键盘
9.Android Webview是否应该开启硬件加速
由于碎片化问题太多,建议保持默认状态【默认表示由系统决定,不要手动设置】,否则可能产生问题。
10.Cookie同步导致的内存泄漏
使用CookieSyncManager同步时,会永久引用第一个acitivity的的Context,为了避免此种情况,请使用ApplicationContext
if (Build.VERSION.SDK_INT < 21) {
android.webkit.CookieSyncManager.createInstance(context.getApplicationContext());
}
11. 30x重定向问题
Android Webview重定向可能导致Android 5.0和5.0之前的Webview内核死锁,而且会导致资源无法释放。一旦内核死锁,那么整个app必须重启才能加载网页,否则一直处于空白状态。
12.loadUrl(url,map)方法加载带hash(带#号)的url导致刷新问题或请求头缓存问题。
① 如果调用loadUrl(url,map)方法去加载资源,那么在此调用loadUrl(ur),reload,loadUrl(url,map)造成无法刷新的问题。这个现象主要出现在Android 8.0的系统中。
可尝试调用如下url尝试:
https://baike.baidu.com/item/%E9%83%8E%E5%B9%B3/58857#/
https://baike.baidu.com/item/%E9%83%8E%E5%B9%B3/58857#/?a=123
https://baike.baidu.com/item/%E9%83%8E%E5%B9%B3/58857#3
②loadUrl(url,map) 第二个参数map中传入的数据用于请求头,此外这个请求头数据会被webview缓存下来,刷新时,请求头中的数据还是原来的,因此,不适用传入需要进程变化的“状态”信息。
解决方法:不要使用loadUrl(url,map),推荐使用loadUrl(url),如果非要传输参数,还不如在url中添加参数。
13.Android 4.2.2 系统注入javascript脚本导致页面循环刷新,导致内核闪退。
Android 4.2.2进行了一次内核调整,但是遗留了一部分bug,就是在js脚本注入的时候,必须得添加 “javascript:”前缀,否则页面将无限刷新,最后ANR。因此,这里建议任何脚本,必须添加 "javscript:"前缀。
14.copyBackForwardList调用时引起空指针问题
部分手机上调用copyBackForwardList会出现空指针问题,需要处理