WebView的实现主要依靠WebView和WebSettings这两个类来实现。WebView提供容器,WebSetting设置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;
}
}
xml文件:
<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哈哈~