业务场景:
MainActivity
中有4个tab,分别为webview加载斗鱼主页
,视频播放,webview加载五星体育
,地图等四个模块。在加载web的时候发现内存泄露。
分别参考了以下webview 内存泄漏方案:
WebView内存泄漏--解决方法小结
Webview内存泄漏与内存占用过大OOM的优化
Android WebView中那些不得不解决的坑~~
WebView内存泄露的解决方案
- 首先不能直接在xml写webview组件,用FrameLayout做容器,java中动态添加:
...
mWebView = new WebView(MyApplication.getContext());
mLlayout_webview.addView(mWebView);
-
弱引用
经测试,通过给webview所在的activity设置为独立进程,然后在改activity的ondestory()方法干掉进程就可以了。Acitvity中的代码
@Override
protected void onDestroy() {
unbinder.unbind();
if (EventBus.getDefault().isRegistered(this)) {
EventBus.getDefault().unregister(this);
}
tellServiceUnbind();
unbindService(serviceConnection);
releaseResource();
/**
* 解决Activity中
* https://www.cnblogs.com/ganchuanpu/p/9182968.html
* 为加载WebView的界面开启新进程,在该页面退出之后关闭这个进程。
*/
android.os.Process.killProcess(android.os.Process.myPid());
super.onDestroy();
}
完整的webview 代码
public class WuXingFragment extends BaseFragment {
private WebSettings webSettings;
public static WuXingFragment getInstance() {
WuXingFragment fragment = new WuXingFragment();
return fragment;
}
private static final String url = "http://sports.sina.com.cn/gsports.shtml#263363145";
private View mView;
private WebView mWebView;
private RelativeLayout loading_over;
private boolean isSuccess = false;
private boolean isError = false;
private LinearLayout ll_control_error,mLlayout_webview;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mView = inflater.inflate(R.layout.layout_webview, container, false);
mWebView = new WebView(MyApplication.getContext());
mLlayout_webview = mView.findViewById(R.id.llayout_webview);
mLlayout_webview.addView(mWebView);
return mView;
}
@Override
public void onResume() {
super.onResume();
// webview 优化 据说可以省电
webSettings.setJavaScriptEnabled(true);
}
@Override
public void onStop() {
super.onStop();
// webview 优化 据说可以省电
webSettings.setJavaScriptEnabled(false);
}
private void doAction() {
webSettings = mWebView.getSettings();
mWebView.setInitialScale(25);
webSettings.setJavaScriptEnabled(true);
webSettings.setJavaScriptEnabled(true);
webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
webSettings.setUseWideViewPort(true);//关键点
webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NARROW_COLUMNS);
webSettings.setDisplayZoomControls(false);
webSettings.setJavaScriptEnabled(true); // 设置支持javascript脚本
webSettings.setAllowFileAccess(true); // 允许访问文件
// webSettings.setBuiltInZoomControls(true); // 设置显示缩放按钮
// webSettings.setSupportZoom(true); // 支持缩放
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
webSettings.setDomStorageEnabled(true);
webSettings.setPluginState(WebSettings.PluginState.ON);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
}
mWebView.loadUrl(url);
//设置视图客户端
mWebView.setWebViewClient(new MyWebViewClient(getActivity()));
// mWebView.setWebViewClient();
}
class MyWebViewClient extends WebViewClient {
protected WeakReference<Activity> activityRef;
public MyWebViewClient(Activity activity) {
this.activityRef = new WeakReference<>(activity);
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) { //重写此方法表明点击网页里面的链接还是在当前的webview里跳转,不跳到浏览器那边
if (this == null) {
return false;
}
Activity activity = activityRef.get();
if (activity != null) {
//调用拨号程序
if (url.startsWith("mailto:") || url.startsWith("geo:") || url.startsWith("tel:") || url.startsWith("smsto:")) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
activity.startActivity(intent);
return true;
}
}
return false;
}
@Override
public void onPageFinished(WebView view, String url) {
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
//6.0以下执行
updateUI();
}
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
//6.0以上执行
updateUI();
}
}
private void updateUI() {
isError = true;
isSuccess = false;
mWebView.setVisibility(View.GONE);
ll_control_error.setVisibility(View.VISIBLE);
}
@Override
public void onDestroyView() {
release();
super.onDestroyView();
}
@Override
public void onDestroy() {
release();
super.onDestroy();
}
private void release() {
if (null != mWebView) {
// 如果先调用destroy()方法,则会命中if (isDestroyed()) return;这一行代码,需要先onDetachedFromWindow(),再
// destory()
ViewParent parent = mWebView.getParent();
if (parent != null) {
((ViewGroup) parent).removeView(mWebView);
}
mWebView.stopLoading();
// 退出时调用此方法,移除绑定的服务,否则某些特定系统会报错
mWebView.getSettings().setJavaScriptEnabled(false);
mWebView.clearHistory();
mWebView.clearView();
mWebView.removeAllViews();
mWebView.destroy();
}
releaseAllWebViewCallback();
}
// 这个方法我这里暂时没起作用
public void releaseAllWebViewCallback() {
if (android.os.Build.VERSION.SDK_INT < 16) {
try {
Field field = WebView.class.getDeclaredField("mWebViewCore");
field = field.getType().getDeclaredField("mBrowserFrame");
field = field.getType().getDeclaredField("sConfigCallback");
field.setAccessible(true);
field.set(null, null);
} catch (NoSuchFieldException e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
} catch (IllegalAccessException e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
}
} else {
try {
Field sConfigCallback = Class.forName("android.webkit.BrowserFrame").getDeclaredField("sConfigCallback");
if (sConfigCallback != null) {
sConfigCallback.setAccessible(true);
sConfigCallback.set(null, null);
}
} catch (NoSuchFieldException e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
} catch (ClassNotFoundException e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
} catch (IllegalAccessException e) {
if (BuildConfig.DEBUG) {
e.printStackTrace();
}
}
}
}
}
网友评论