WebView你所不知道的细节

WebView的实现主要依靠WebView和WebSettings这两个类来实现。WebView提供容器,WebSetting设置WebView支持的属性。

WebView使用过程中需要注意的地方

1、在实例化WebView的时候尽量不要使用当前Activity的引用。用代码New一个WebView而不是在XML中静态写入
我曾经看到有个哥们利用LeakCanary检测过传入当前Activity引用时是否会出现内存泄露,结果是没有。接着换成Application传入,与之前传入的Activity引用进行对比发现,虽然两者都不会造成内存泄露,但是使用Application要使用Activity时所消耗的内存少20~30MB。所以,建议直接使用Application。

即WebView实例化的时候不要采用这种方式
WebView webView = new WebView(this);
应该采用这种方式
WebView webView = new WebView(App.getContext());

示例:

private WebView webView;
webView = new WebView(App.getContext());
//一定要设置WebView的LayoutParams,并且值MATCH_PARENT。否则的话就会出现有的网页无法加载的情况
webView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
        ViewGroup.LayoutParams.MATCH_PARENT));
binding.webviewContainer.addView(webView); 

2、WebView资源的释放。页面销毁之前勿忘释放WebView资源。具体释放规则可以看下面这段代码

private void clearWebViewResource(){    
    if (webView != null){        
        webView.removeAllViews();        
        //在5.1上如果不加上这句话就会出现内存泄露。这是5.1的bug 
        // mComponentCallbacks导致的内存泄漏       
        ((ViewGroup)webView.getParent()).removeView(webView);
        webView.setTag(null);        
        webView.clearHistory();        
        webView.destroy();       
        webView = null;    
     }
}
基于以上介绍提供的Demo示例

xml文件:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">

    <data class=".WebViewBinding">

        <import type="android.view.View" />
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <RelativeLayout
            android:id="@+id/title"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:background="@android:color/background_dark">

            <TextView
                android:id="@+id/back"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:drawableLeft="@drawable/back"
                android:gravity="center"
                android:onClick="onClick"
                android:text="返回"
                android:textColor="@android:color/white"
                android:textSize="16sp" />

            <TextView
                android:id="@+id/close"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_marginLeft="10dp"
                android:layout_toRightOf="@id/back"
                android:gravity="center"
                android:onClick="onClick"
                android:text="关闭"
                android:textColor="@android:color/white"
                android:textSize="16sp" />
        </RelativeLayout>

        <RelativeLayout
            android:id="@+id/webview_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@+id/title"
            tools:context="com.syz.example.webview.WebViewActivity">

        </RelativeLayout>
    </RelativeLayout>
</layout>

对应的Activity:

package com.syz.example.webview;

import android.app.ProgressDialog;
import android.content.Intent;
import android.databinding.DataBindingUtil;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import com.syz.example.App;
import com.syz.example.R;
import com.syz.example.WebViewBinding;

import static com.syz.example.R.id.close;

/**
 * Create By Elven_Shi
 */
public class WebViewActivity extends AppCompatActivity implements View.OnClickListener {

    public static final String TAG = "WebViewActivity";

    private static final String SERVER_URL = "http://192.168.0.199:8080/mobile";
//    private static final String SERVER_URL = "http://baidu.com";

    private WebView webView;

    private WebViewBinding binding;

    private ProgressDialog progressDialog;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_web_view);
        webView = new WebView(App.getContext());

        //一定要设置WebView的LayoutParams,并且值MATCH_PARENT。否则的话就会出现有的网页无法加载的情况
        webView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT));
        binding.webviewContainer.addView(webView);

        progressDialog = new ProgressDialog(this);
        initView();
    }


    private void initView() {
        binding.close.setVisibility(View.GONE);
        WebSettings webSettings = webView.getSettings();

        webSettings.setPluginState(WebSettings.PluginState.ON);
        webSettings.setDefaultTextEncodingName("utf-8");
        webSettings.setLoadWithOverviewMode(true);

        webSettings.setJavaScriptEnabled(true);//支持js
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);//设置通过js打开新的窗口
//        webSettings.setSupportZoom(true);//设置可以支持缩放
//        webSettings.setBuiltInZoomControls(false);//支持缩放,出现缩放工具。必须和setSupportZoom配合使用
//        webSettings.setUseWideViewPort(true);//扩大比例的缩放
        webSettings.setSupportMultipleWindows(false);//是否支持多窗口模式
//        webSettings.setDisplayZoomControls(false);//隐藏Zoom缩放按钮
//        webSettings.setRenderPriority(WebSettings.RenderPriority.HIGH);//提高渲染等级

        //自适应屏幕
        webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);

        webSettings.setAppCacheEnabled(true);//启用缓存
        webSettings.setDomStorageEnabled(true);//使用localStorage则必须打开
        webSettings.setBlockNetworkImage(true);//首先让图片阻塞,不加载图片
        webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);//先加载缓存,在请求网络

//        String dir = getDir("database", Context.MODE_PRIVATE).getPath();
//        webSettings.setDatabasePath(dir);//设置数据库路径
//        webSettings.setGeolocationEnabled(true);
//        webSettings.setGeolocationDatabasePath(dir);// 设置地理位置数据库路径
//        webSettings.setDatabaseEnabled(true);

        webView.loadUrl(SERVER_URL);

        //WebChromeClient主要是处理解析,渲染网页等浏览器做的事情。
        // WebChromeClient是辅助WebView处理Javascript的对话框,网站图标,网站title,加载进度等
        //一般情况下,都是需要设置WebChromeClient的。
        setWebChromeClient(webView);

        setWebViewClient(webView);
    }

    private void showProgress() {
        progressDialog.show();
    }

    private void closeDialog() {
        progressDialog.cancel();
    }

    /**
     * 使用WebChromeClient
     *
     * @param webView
     */
    private void setWebChromeClient(final WebView webView) {
        webView.setWebChromeClient(new WebChromeClient() {
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                // 获得网页的加载进度 newProgress为当前加载百分比
                super.onProgressChanged(view, newProgress);
                Log.e(TAG, "onProgressChanged>>>" + newProgress);

            }

            @Override
            public void onReceivedTitle(WebView view, String title) {
                // 获取网页的title,客户端可以在这里动态修改页面的title
                // 另外,当加载错误时title为“找不到该网页”
                super.onReceivedTitle(view, title);
                Log.e(TAG, "onReceivedTitle>>>" + title);
            }


        });
    }

    /**
     * 采用WebViewClient
     *
     * @param webView
     */
    private void setWebViewClient(final WebView webView) {
        webView.setWebViewClient(new WebViewClient() {

            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
                //页面开始加载时
                Log.e(TAG, "onPageStarted---开始加载页面");
                showProgress();
            }

            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
                Log.e(TAG, "onPageFinished---页面加载结束");
                closeDialog();
                //页面加载好,再加载图片
                webView.getSettings().setBlockNetworkImage(false);
            }

            /**
             * 该方法只有在API 23以上版本才可以使用
             * @param view
             * @param request
             * @param error
             */
            @RequiresApi(api = Build.VERSION_CODES.M)
            @Override
            public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
                super.onReceivedError(view, request, error);
                Log.e(TAG, "网络请求发生错误>>>>>"+error.getDescription());
            }

            @Override
            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
                super.onReceivedError(view, errorCode, description, failingUrl);
                // 这里进行无网络或错误处理,具体可以根据errorCode的值进行判断
                Log.e(TAG, "网络请求发生错误description>>>" + description);
            }

            /**
             * 该方法只有在API 21以上版本才可以使用
             * @param view
             * @param request
             * @return
             */
            @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
                Log.e(TAG, "shouldOverrideUrlLoading");
                view.loadUrl(request.getUrl().toString());
                return true;
            }

            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {

                /**
                 * 网页跳转:
                 * 1.在当前的webview跳转到新连接。在这里可以截获url,根据url判断是否是下载url,还是普通链接
                 * 如果是普通链接,则直接调用view.loadUrl(url);并返回true。如果是下载链接,则做出下载处理,并返回false表示不跳转
                 *
                 * 2.调用系统浏览器跳转到新网页
                 * openViewByBrowser();
                 */
                Log.e(TAG, "old shouldOverrideUrlLoading>>>" + url);
                view.loadUrl(url);
                return true;
            }
        });
    }

    /**
     * 利用浏览器打开网页
     */
    private void openViewByBrowser(String url) {
        Uri uri = Uri.parse(url);
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        startActivity(intent);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        clearWebViewResource();
    }

    private void clearWebViewResource() {
        if (webView != null) {
            webView.removeAllViews();
            //在5.1的机型上如果不加上这句话就会出现内存泄露。这是5.1的bug
            ((ViewGroup) webView.getParent()).removeView(webView);
            webView.setTag(null);
            webView.clearHistory();
            webView.destroy();
            webView = null;
        }
    }


    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.back:
                //是否可以继续返回,如果true则返回到上一层页面,如果false则关闭页面
                if (webView.canGoBack()) {
                    webView.goBack();
                    binding.close.setVisibility(View.VISIBLE);
                } else {
                    finish();
                }

                break;
            case close:
                finish();
                break;
            default:
                break;
        }
    }

    /**
     * back键执行操作
     *
     * @param keyCode
     * @param event
     * @return
     */
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
            webView.goBack();
            binding.close.setVisibility(View.VISIBLE);
            return true;
        }
        return super.onKeyDown(keyCode, event);
    }
}

关于效果就不用展示了。AS的屏幕录制需要PS做成gif图片,由于电脑上面没有PS。也懒得下载。就不放gif图片了。放一张截图吧,虽然并没有什么卵用O(∩_∩)O哈哈~
这里写图片描述

最后顺带推荐几篇WebView相关的文章
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值