Android控件十六:WebView使用(二):WebViewClient与常用事件监听

原文:https://blog.csdn.net/harvic880925/article/details/51523983

一、WebViewClient

1、概述
前面我们虽然实现了交互,但可能我们会有一个很简单的需求,就是在开始加载网页的时候显示进度条,加载结束以后隐藏进度条,这要怎么做?
这些简单的需求,Android开发的老人们肯定都已经想到了,这些有关各种事件的回调都被封装在WebViewClient类中了,在WebViewClient中有各种的回调方法,就是在某个事件发生时供我们监听
使用方法如下:

	mWebView.setWebViewClient(new WebViewClient(){
		@Override
		public void onPageStarted(WebView view, String url, Bitmap favicon) {
			super.onPageStarted(view, url, favicon);
			Log.d(TAG,"onPageStarted");
		}
	 
		@Override
		public void onPageFinished(WebView view, String url) {
			super.onPageFinished(view, url);
			Log.d(TAG,"onPageFinished");
		}
	});

2、WebViewClient中函数概述
在WebViewClient中除了上面我们列举出的onPageStarted、onPageFinished还有很多其它函数,分别是

		/**
		* 在开始加载网页时会回调
		*/
		public void onPageStarted(WebView view, String url, Bitmap favicon) 
		
		/**
		* 在结束加载网页时会回调
		*/
		public void onPageFinished(WebView view, String url)
		
		/**
		* 拦截 url 跳转,在里边添加点击链接跳转或者操作
		*/
		public boolean shouldOverrideUrlLoading(WebView view, String url)
		
		/**
		* 加载错误的时候会回调,在其中可做错误处理,比如再请求加载一次,或者提示404的错误页面
		*/
		public void onReceivedError(WebView view, int errorCode,String description, String failingUrl)
		
		/**
		* 当接收到https错误时,会回调此函数,在其中可以做错误处理
		*/
		public void onReceivedSslError(WebView view, SslErrorHandler handler,SslError error)
		
		/**
		* 在每一次请求资源时,都会通过这个函数来回调
		*/
		public WebResourceResponse shouldInterceptRequest(WebView view,String url) {
			return null;
		}		

3、WebViewClient之shouldOverrideUrlLoading
该函数的完整声明如下:

public boolean shouldOverrideUrlLoading(WebView view, String url)

这个函数会在加载超链接时回调过来;所以通过重写shouldOverrideUrlLoading,可以实现对网页中超链接的拦截;
返回值是boolean类型,表示是否屏蔽WebView继续加载URL的默认行为,因为这个函数是WebView加载URL前回调的,所以如果我们return true,则WebView接下来就不会再加载这个URL了,所有处理都需要在WebView中操作,包含加载。
如果我们return false,则系统就认为上层没有做处理,接下来还是会继续加载这个URL的。WebViewClient默认就是return false的:

shouldOverrideUrlLoading实例:
由于每次超链接在加载前都会先走shouldOverrideUrlLoading回调,所以我们如果想拦截某个URL,将其转换成其它URL可以在这里做。

		     	public class MyActivity extends Activity {
				private WebView mWebView;
			 
				private ProgressDialog mProgressDialog;
				private String TAG = "qijian";
				@Override
				public void onCreate(Bundle savedInstanceState) {
					super.onCreate(savedInstanceState);
					setContentView(R.layout.main);
			 
					mWebView = (WebView)findViewById(R.id.webview);
					mProgressDialog = new ProgressDialog(this);
					mWebView.getSettings().setJavaScriptEnabled(true);
			 
					mWebView.setWebViewClient(new WebViewClient(){
					@Override
					public boolean shouldOverrideUrlLoading(WebView view, String url) {
						if (url.contains("blog.csdn.net")){
							view.loadUrl("http://www.baidu.com");
						}
						return false;
					}
				}  
					mWebView.loadUrl("http://blog.csdn.net/harvic880925");
				}
			}		

4、WebViewClient之onReceivedError
onReceivedError的完整声明如下:

public void onReceivedError(WebView view, int errorCode,String description, String failingUrl)

加载错误的时候会产生这个回调,在其中可做错误处理,比如我们可以加载一个错误提示页面
这里有四个参数:

		WebView view:当前的WebView实例
		int errorCode:错误码
		String description:错误描述
		String failingUrl:当前出错的URL

实例:

		1,提供错误的URL
			mWebView.loadUrl("ht://blog.csdn.net/harvic880925");
		2,重写该方法
			mWebView.setWebViewClient(new WebViewClient(){
				@Override
				public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
					super.onReceivedError(view, errorCode, description, failingUrl);
					mWebView.loadUrl("file:///android_asset/error.html");
				}
			});

5、WebViewClient之onReceivedSslError
我们知道HTTPS协议是通过SSL来通信的,所以当使用HTTPS通信的网址(以https://开头的网站)出现错误时,就会通过onReceivedSslError回调通知过来,
它的函数声明为:

		/**
		* 当接收到https错误时,会回调此函数,在其中可以做错误处理
		*/
		public void onReceivedSslError(WebView view, SslErrorHandler handler,SslError error)
			
			WebView view:当前的WebView实例
			SslErrorHandler handler:当前处理错误的Handler,它只有两个函数SslErrorHandler.proceed()和SslErrorHandler.cancel(),
			SslErrorHandler.proceed()表示忽略错误继续加载,SslErrorHandler.cancel()表示取消加载。
			在onReceivedSslError的默认实现中是使用的SslErrorHandler.cancel()来取消加载,所以一旦出来SSL错误,HTTPS网站就会被取消加载了,如果想忽略错误继续加载就只有重写onReceivedSslError,并在其中调用SslErrorHandler.proceed()
			SslError error:当前的的错误对象,SslError包含了当前SSL错误的基本所有信息,大家自己去看下它的方法吧,这里就不再展开了。

实例:

		public class MyActivity extends Activity {
			private WebView mWebView;
		 
			private ProgressDialog mProgressDialog;
			private String TAG = "qijian";
			@Override
			public void onCreate(Bundle savedInstanceState) {
				super.onCreate(savedInstanceState);
				setContentView(R.layout.main);
		 
				mWebView = (WebView)findViewById(R.id.webview);
				mProgressDialog = new ProgressDialog(this);
				mWebView.getSettings().setJavaScriptEnabled(true);
		 
				mWebView.setWebViewClient(new WebViewClient(){
					@Override
					public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
						super.onReceivedSslError(view, handler, error);
						Log.e(TAG,"sslError:"+error.toString());
					}
		 
				mWebView.loadUrl("https://www.12306.cn/");
			}
		}

注意:
当使用SslErrorHandler.proceed()来继续加载时:
1,注释掉super.onReceivedSslError(view, handler, error);,取消系统的默认行为,默认是取消继续加载的
2,调用handler.proceed();来忽略错误继续加载页面。
在SSL发生错误时,onReceivedError会被回调吗?——不会

6、WebViewClient之shouldInterceptRequest
在每一次请求资源时,都会通过这个函数来回调,比如超链接、JS文件、CSS文件、图片等,也就是说浏览器中每一次请求资源时,都会回调回来,无论任何资源!但是必须注意的是shouldInterceptRequest函数是在非UI线程中执行的,在其中不能直接做UI操作,如果需要做UI操作,则需要利用Handler来实现,该函数声明如下:

public WebResourceResponse shouldInterceptRequest(WebView view,String url) {
				return null;
			}

该函数会在请求资源前调用,我们可以通过返回WebResourceResponse的处理结果来让WebView直接使用我们的处理结果。如果我们不想处理,则直接返回null,系统会继续加载该资源。

实例:假如网页中需要加载本地的图片,我们就可以通过拦截shouldInterceptRequest,并返回结果即可
HTML中img字段加载图片的地址是:http://localhost/qijian.png,
在Android中,当发现要加载这个地址的资源时,我们将它换成本地的图片

HTML中:

			<!DOCTYPE html>
			<html lang="en">
			<head>
				<meta charset="UTF-8">
				<title>Title</title>
			</head>
			<body>
				<h1 id="h">欢迎光临启舰的blog</h1>
				<img src="http://localhost/qijian.png"/>
			</body>
			</html>

Java中:

			public class MyActivity extends Activity {
			private WebView mWebView;
		 
			private ProgressDialog mProgressDialog;
			private String TAG = "qijian";
			@Override
			public void onCreate(Bundle savedInstanceState) {
				super.onCreate(savedInstanceState);
				setContentView(R.layout.main);
		 
				mWebView = (WebView)findViewById(R.id.webview);
				mProgressDialog = new ProgressDialog(this);
				mWebView.getSettings().setJavaScriptEnabled(true);
		 
		 
				mWebView.setWebViewClient(new WebViewClient(){
					@Override
					public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
						try {
							if (url.equals("http://localhost/qijian.png")) {
								AssetFileDescriptor fileDescriptor =  getAssets().openFd("s07.jpg");
								InputStream stream = fileDescriptor.createInputStream();
								WebResourceResponse response = new WebResourceResponse("image/png", "UTF-8", stream);
								return response;
							}
						}catch (Exception e){
							Log.e(TAG,e.getMessage());
						}
						return super.shouldInterceptRequest(view, url);
					}
				});
		 
				mWebView.loadUrl("file:///android_asset/web.html");
		}        

7、WebViewClient之其余函数
上面讲了常用的大部分函数,还些一些函数,并不怎么用,这里由于篇幅有限就不再讲了,把函数声明和作用列出来供大家参考

	   /**
		* 在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次
		*/
		public void onLoadResource(WebView view, String url) 
		
		/**
		*  (WebView发生改变时调用) 
		*  可以参考http://www.it1352.com/191180.html的用法
		*/
		public void onScaleChanged(WebView view, float oldScale, float newScale)
		
		/**
		* 重写此方法才能够处理在浏览器中的按键事件。
		* 是否让主程序同步处理Key Event事件,如过滤菜单快捷键的Key Event事件。
		* 如果返回true,WebView不会处理Key Event,
		* 如果返回false,Key Event总是由WebView处理。默认:false
		*/
		public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event)
		
		/**
		* 是否重发POST请求数据,默认不重发。
		*/
		onFormResubmission(WebView view, Message dontResend, Message resend)
		
		/**
		* 更新访问历史
		*/
		doUpdateVisitedHistory(WebView view, String url, boolean isReload)
		
		/**
		* 通知主程序输入事件不是由WebView调用。是否让主程序处理WebView未处理的Input Event。
		* 除了系统按键,WebView总是消耗掉输入事件或shouldOverrideKeyEvent返回true。
		* 该方法由event 分发异步调用。注意:如果事件为MotionEvent,则事件的生命周期只存在方法调用过程中,
		* 如果WebViewClient想要使用这个Event,则需要复制Event对象。
		*/
		onUnhandledInputEvent(WebView view, InputEvent event)
		
		/**
		* 通知主程序执行了自动登录请求。
		*/
		onReceivedLoginRequest(WebView view, String realm, String account, String args)
		
		/**
		* 通知主程序:WebView接收HTTP认证请求,主程序可以使用HttpAuthHandler为请求设置WebView响应。默认取消请求。
		*/
		onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm)
		
		/**
		* 通知主程序处理SSL客户端认证请求。如果需要提供密钥,主程序负责显示UI界面。
		* 有三个响应方法:proceed(), cancel() 和 ignore()。
		* 如果调用proceed()和cancel(),webview将会记住response,
		* 对相同的host和port地址不再调用onReceivedClientCertRequest方法。
		* 如果调用ignore()方法,webview则不会记住response。该方法在UI线程中执行,
		* 在回调期间,连接被挂起。默认cancel(),即无客户端认证
		*/
		onReceivedClientCertRequest(WebView view, ClientCertRequest request)
二、其它事件处理

上面讲了有关WebViewClient的用法,但其中还有一些小问题是WebViewClient无法解决的,比如返回按键、滚动事件监听等

1、返回按键
如果用webview点链接看了很多页以后,如果不做任何处理,点击系统“Back”键,整个浏览器会调用finish()而结束自身,如果希望浏览的网页回退而不是退出浏览器,需要在当前Activity中处理并消费掉该Back事件。

覆盖Activity类的onKeyDown(int keyCoder,KeyEvent event)方法。

		public class MyActivity extends Activity {
			private WebView mWebView;
		 
			private ProgressDialog mProgressDialog;
			private String TAG = "qijian";
			@Override
			public void onCreate(Bundle savedInstanceState) {
				super.onCreate(savedInstanceState);
				setContentView(R.layout.main);
		 
				mWebView = (WebView)findViewById(R.id.webview);
				mProgressDialog = new ProgressDialog(this);
				mWebView.getSettings().setJavaScriptEnabled(true);
				mWebView.setWebViewClient(new WebViewClient());
		 
				mWebView.loadUrl("http://blog.csdn.net/harvic880925/");
			}
		 
			@Override
			public boolean onKeyDown(int keyCode, KeyEvent event) {
				//改写物理返回键的逻辑
				if(keyCode==KeyEvent.KEYCODE_BACK) {
					if(mWebView.canGoBack()) {
						mWebView.goBack();//返回上一页面 
						return true;
					} else {
						System.exit(0);//退出程序 
					}
				}
				return super.onKeyDown(keyCode, event);
			}
		}

2、滚动事件监听
我们都知道监听滚动事件一般都是设置setOnScrollChangedListener,可惜的是 WebView并没有给我们提供这样的方法,但是我们可以重写WebView,覆盖里面的一个方法: protected void onScrollChanged(final int l, final int t, final int oldl,final int oldt){} 然后再对外提供一个接口,

		public class MyWebView extends WebView {
 
			private OnScrollChangedCallback mOnScrollChangedCallback;
		 
			public MyWebView(Context context) {
				super(context);
			}
		 
			public MyWebView(Context context, AttributeSet attrs) {
				super(context, attrs);
			}
		 
			public MyWebView(Context context, AttributeSet attrs, int defStyleAttr) {
				super(context, attrs, defStyleAttr);
			}
		 
			@Override
			protected void onScrollChanged(int l, int t, int oldl, int oldt) {
				super.onScrollChanged(l, t, oldl, oldt);
				if (mOnScrollChangedCallback != null) {
					mOnScrollChangedCallback.onScroll(l,t,oldl,oldt);
				}
			}
		 
			public OnScrollChangedCallback getOnScrollChangedCallback() {
				return mOnScrollChangedCallback;
			}
		 
			public void setOnScrollChangedCallback(
					final OnScrollChangedCallback onScrollChangedCallback) {
				mOnScrollChangedCallback = onScrollChangedCallback;
			}
		 
			public static interface OnScrollChangedCallback {
				public void onScroll(int left,int top ,int oldLeft,int oldTop);
			}
	}

3、如何强制使用外部浏览器打开网页
如果不想在 webview 中显示网页,而是直接跳转到浏览器的话,可以像下边那样调用。

			Uri uri = Uri.parse("http://www.example.com"); 
			Intent intent = new Intent(Intent.ACTION_VIEW, uri); 
			startActivity(intent);
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值