WebView性能优化

来源:互联网 发布:软件需求分析常见问题 编辑:程序博客网 时间:2024/06/06 01:09

WebView性能优化

作者: 郭嘉
邮箱: guoxiaoxingv@163.com
博客: https://guoxiaoxing.github.io/
知乎: https://www.zhihu.com/people/allen-wells

关于作者

Android Coder一枚, 目前就职于杭州大搜车汽车汽车服务有限公司。爱技术、爱烹饪、爱小提琴、爱一切新鲜有趣的事物。
人生格言: 不想当程序员的歌手不是好厨师。

关于文章

作者的每一篇文章都会同时发布在Github、CSDN和知乎上, 文章顶部也会附上Github上的文章链接和代码链接。如果文章中有什么疑问欢迎发邮件与
我交流, 对于交流的问题, 请描述清楚并附上代码与日志, 我一般都会给予回复。如果文章中有什么错误, 也欢迎斧正。如果你觉得本文章对你
有所帮助, 也欢迎去star文章, 关注文章的最新的动态。

本系列文章讨论WebView的各种用法以及使用技巧, 一共包含三篇文章:

WebView基本用法
WebView代码交互
WebView性能优化

一 优化网页加载速度

默认情况html代码下载到WebView后,webkit开始解析网页各个节点,发现有外部样式文件或者外部脚本文件时,会异步发起网络请求下载文件,但如果
在这之前也有解析到image节点,那势必也会发起网络请求下载相应的图片。在网络情况较差的情况下,过多的网络请求就会造成带宽紧张,影响到css或
js文件加载完成的时间,造成页面空白loading过久。解决的方法就是告诉WebView先不要自动加载图片,等页面finish后再发起图片加载。

设置WebView, 先禁止加载图片

WebSettings webSettings = mWebView.getSettings();//图片加载if(Build.VERSION.SDK_INT >= 19){    webSettings.setLoadsImagesAutomatically(true);}else {    webSettings.setLoadsImagesAutomatically(false);}

覆写WebViewClient的onPageFinished()方法, 页面加载结束后再加载图片

@Overridepublic void onPageFinished(WebView view, String url) {    super.onPageFinished(view, url);    if (!view.getSettings().getLoadsImagesAutomatically()) {        view.getSettings().setLoadsImagesAutomatically(true);    }}

注意: 4.4以上系统在onPageFinished时再恢复图片加载时,如果存在多张图片引用的是相同的src时,会只有一个image标签得到加载,因而对于这样的系统我们就先直接加载。

二 硬件加速页面闪烁问题

4.0以上的系统我们开启硬件加速后,WebView渲染页面更加快速,拖动也更加顺滑。但有个副作用就是,当WebView视图被整体遮住一块,然后突然恢复时(比如使用SlideMenu将WebView从侧边
滑出来时),这个过渡期会出现白块同时界面闪烁。解决这个问题的方法是在过渡期前将WebView的硬件加速临时关闭,过渡期后再开启,如下所示:

过度前关闭硬件加速

if(Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB){    mWebView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);}

过度前开启硬件加速

if(Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB){    mWebView.setLayerType(View.LAYER_TYPE_HARDWARE, null);}

以上三篇, 大致就说这么多, 在实际的项目中我们通常会自己去封装一个H5Activity用来统一显示H5页面, 下面就提供了完整的H5Activity, 封装了WebView各种特性与jockeyjs代码交互。

该H5Activity提供WebView常用设置、H5页面解析、标题解析、进度条显示、错误页面展示、重新加载等功能。可以拿去稍作改造, 用于自己的项目中。

package com.guoxiaoxing.webview;import android.content.Context;import android.graphics.Bitmap;import android.net.ConnectivityManager;import android.net.NetworkInfo;import android.os.Build;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.Toolbar;import android.text.TextUtils;import android.util.Log;import android.view.KeyEvent;import android.view.View;import android.view.Window;import android.webkit.JsResult;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 android.widget.ProgressBar;import com.jockeyjs.Jockey;import com.jockeyjs.JockeyImpl;/** * Author: guoxiaoxing * Date: 16/7/21 下午4:03 * Function: H5Activity 提供各种功能载入Web页面 * <p> * For more information, you can visit https://github.com/guoxiaoxing or contact me by * guoxiaoxingv@163.com */public class H5Activity extends AppCompatActivity {    public static final String H5_URL = "H5_URL";    private static final String JOCKEY_EVENT_NAME = "JOCKEY_EVENT_NAME";    private static final String TAG = H5Activity.class.getSimpleName();    private Toolbar mToolbar;    private ProgressBar mProgressBar;    private Jockey mJockey;    private WebView mWebView;    private WebViewClient mWebViewClient;    private WebChromeClient mWebChromeClient;    private String mUrl;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);        setContentView(R.layout.activity_h5);        setupView();        setupSettings();    }    @Override    protected void onStart() {        super.onStart();        setupJockey();        setupData();    }    private void setupView() {        mToolbar = (Toolbar) findViewById(R.id.h5_toolbar);        mProgressBar = (ProgressBar) findViewById(R.id.h5_progressbar);        mWebView = (WebView) findViewById(R.id.h5_webview);    }    private void setupSettings() {        mWebView.setScrollBarStyle(WebView.SCROLLBARS_INSIDE_OVERLAY);        mWebView.setHorizontalScrollBarEnabled(false);        mWebView.setOverScrollMode(WebView.OVER_SCROLL_NEVER);        WebSettings mWebSettings = mWebView.getSettings();        mWebSettings.setSupportZoom(true);        mWebSettings.setLoadWithOverviewMode(true);        mWebSettings.setUseWideViewPort(true);        mWebSettings.setDefaultTextEncodingName("utf-8");        mWebSettings.setLoadsImagesAutomatically(true);        //JS        mWebSettings.setJavaScriptEnabled(true);        mWebSettings.setJavaScriptCanOpenWindowsAutomatically(true);        mWebSettings.setAllowFileAccess(true);        mWebSettings.setUseWideViewPort(true);        mWebSettings.setDatabaseEnabled(true);        mWebSettings.setLoadWithOverviewMode(true);        mWebSettings.setDomStorageEnabled(true);        //缓存        ConnectivityManager connectivityManager = (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);        NetworkInfo info = connectivityManager.getActiveNetworkInfo();        if (info != null && info.isConnected()) {            String wvcc = info.getTypeName();            Log.d(TAG, "current network: " + wvcc);            mWebSettings.setCacheMode(WebSettings.LOAD_DEFAULT);        } else {            Log.d(TAG, "No network is connected, use cache");            mWebSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);        }        if (Build.VERSION.SDK_INT >= 16) {            mWebSettings.setAllowFileAccessFromFileURLs(true);            mWebSettings.setAllowUniversalAccessFromFileURLs(true);        }        if (Build.VERSION.SDK_INT >= 12) {            mWebSettings.setAllowContentAccess(true);        }        setupWebViewClient();        setupWebChromeClient();    }    private void setupJockey() {        mJockey = JockeyImpl.getDefault();        mJockey.configure(mWebView);        mJockey.setWebViewClient(mWebViewClient);        mJockey.setOnValidateListener(new Jockey.OnValidateListener() {            @Override            public boolean validate(String host) {                return "yourdomain.com".equals(host);            }        });        //TODO set your event handler        mJockey.on(JOCKEY_EVENT_NAME, new EventHandler());    }    private void setupData() {        mUrl = getIntent().getStringExtra(H5_URL);        if (TextUtils.isEmpty(mUrl)) {            //TODO show error page        } else {            mWebView.loadUrl(mUrl);        }    }    private void setupWebViewClient() {        mWebViewClient = new WebViewClient() {            @Override            public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {                //TODO 处理URL, 例如对指定的URL做不同的处理等                return false;            }            @Override            public void onPageFinished(WebView view, String url) {                super.onPageFinished(view, url);            }            @Override            public void onPageStarted(WebView view, String url, Bitmap favicon) {                super.onPageStarted(view, url, favicon);            }            @Override            public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {                super.onReceivedError(view, request, error);            }        };        mWebView.setWebViewClient(mWebViewClient);    }    private void setupWebChromeClient() {        mWebChromeClient = new WebChromeClient() {            @Override            public void onReceivedTitle(WebView view, String title) {                super.onReceivedTitle(view, title);                mToolbar.setTitle(title);            }            @Override            public void onProgressChanged(WebView view, int newProgress) {                super.onProgressChanged(view, newProgress);                mProgressBar.setProgress(newProgress);                if (newProgress == 100) {                    mProgressBar.setVisibility(View.GONE);                } else {                    mProgressBar.setVisibility(View.VISIBLE);                }            }            @Override            public boolean onJsAlert(WebView view, String url, String message, JsResult result) {                return super.onJsAlert(view, url, message, result);            }        };        mWebView.setWebChromeClient(mWebChromeClient);    }    @Override    public boolean onKeyDown(int keyCode, KeyEvent event) {        if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {            mWebView.goBack();            return true;        }        return super.onKeyDown(keyCode, event);    }}
0 0