美文网首页
Android由webview引起的内存泄漏

Android由webview引起的内存泄漏

作者: 城南一霸賈十七 | 来源:发表于2018-11-14 14:09 被阅读30次

    业务场景: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();
                    }
                }
            }
        }
    }
    
    

    相关文章

      网友评论

          本文标题:Android由webview引起的内存泄漏

          本文链接:https://www.haomeiwen.com/subject/otfjfqtx.html