WebView中常见问题总结

原创 2015年11月20日 19:41:08

    最近在项目中遇到对WebView的需求应用,在开发中遇到了几点问题,记录下来以便不时之需。

    1、WebView中获取网页标题的问题:在利用WebView开发的时候,有多种获取页面标题的方法:

     (1)、最常用的方法:重写WebChromeClient的onReceivedTitle方法:

	webview.setWebChromeClient(new WebChromeClient(){
		@Override
		public void onReceivedTitle(WebView view, String title) {
			Toast.makeText(mContext, title, Toast.LENGTH_SHORT).show();
		}
	});

     (2)、利用WebView的getTitle()方法获取:

	webview.getTitle();

           在WebView的大多回调方法的参数中都保留对WebView的引用,可以直接利用该对象获取title,如在WebViewClient的方法onPageFinished中:

	@Override
	public void onPageFinished(WebView view, String url) {
		String title = view.getTitle();
		if (StringUtils.isNullOrEmpty(title)) {
			title = titleStr;
		}
		tv_title_content.setText(title);
	}

      (3)、通过WebView获取前进后退队列,然后得到title,WebView提供了获取前进后退队列的方法供调用:

	WebBackForwardList copyBackForwardList = webview.copyBackForwardList();
	WebHistoryItem currentItem = copyBackForwardList.getCurrentItem();
	if(currentItem!=null){
		String title =currentItem.getTitle();
		Toast.makeText(mContext, title, Toast.LENGTH_SHORT).show();
	}

      当然,利用copyBackForwardList 还可以做其他很多操作。

      综合上面几种获取title的方式,有几点需要注意的地方:① onReceivedTitle()方法在某些机型上执行WebView的goback()方法之后不会调用,故通过在onReceivedTilte中获取title然后自己维护的话,容易造成内容与标题不一致的情况出现,所以,在牵扯到网页内跳转较多的时候建议采用后两种方法;② 在android4.4的手机上onPageFinished()方法会多调用一次,所以复杂的逻辑上最好不要在这个函数中做。
  

    2、利用WebView加载百度地图的网页时出现空白页的问题解决,针对此问题,网上有各种答案,不能说谁对谁错,只能说针对不同的机型或百度地图的不同版本有不同的解决方案,当然,本人也没有针对全部机型进行测试,在这儿只记录我的解决方法:

    // 本人亲测,设置下面几行代码的话,当前日期下的百度地图在大多数手机上展示是没问题的
    webSettings.setJavaScriptEnabled(true);
    webSettings.setAllowFileAccess(true);
    webSettings.setDomStorageEnabled(true);

    另外,也有人说设置如下参数也可解决该问题,但是我在小米3手机上测试没有通过:

    webSettings.setBlockNetworkImage(false);
    webSettings.setBlockNetworkLoads(false);


    3、如果在网页中播放了音频文件,在页面返回之后声音依然在播放问题的解决。如果在页面返回的时候不对音频文件做处理的话,会保持对音频资源的引用,直到其播放完毕,可以在页面的onDestroy()方法中利用WebView的destroy()方法将WebView相关的资源释放掉,但是如果直接调用该方法,有可能会抛异常,可先将WebVew从页面中移除再调用该方法:

	@Override
	protected void onDestroy() {
		try {
			((RelativeLayout) findViewById(R.id.rl_root)).removeView(webview);
			webview.destroy();
		} catch (Exception e) {
			e.printStackTrace();
		}
		super.onDestroy();
	}


    4、自定义错误显示页面解决方案。当WebView加载网页出错时,特别是网络出错时,WebView展示的页面不太友好,这时可通过自定义错误页面的方式改善用户体验。自定义错误页面有两种方式,一种是在WebView所在布局中添加错误页面布局;另外一种是自定义错误网页,将其放在assets文件夹中,在网页出错时加载该错误网页。

    (1) 在布局中添加错误提示布局方式展示自定义错误页面:

         页面布局如下,ViewStub中的布局即为自定义的错误布局。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/rl_root"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <include
        android:id="@+id/rl_title_container"
        layout="@layout/title_include_layout" />

    <ProgressBar
        android:id="@+id/progress_bar"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="4dp"
        android:layout_below="@+id/rl_title_container"
        android:progressDrawable="@drawable/pro_bg" />

    <WebView
        android:id="@+id/webview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/progress_bar" />

    <!-- 默认情况下此布局不会加载,提高性能,网页加载失败时填充 -->

    <ViewStub
        android:id="@+id/vs_nomsg_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/progress_bar"
        android:inflatedId="@+id/ll_nomsg_container"
        android:layout="@layout/common_nomsg_layout" />

</RelativeLayout>

      分别重写WebViewClient中的WebView的onReceivedError()和WebChromeClient中的onProgressChanged()方法处理错误页面展示的逻辑。由于onPageFinished方法在android4.4中会调用两次,所以不在此方法中处理。另,本人测试的机型,如果页面加载出错,均是先调用onReceivedError(),后调用onProgressChanged(),故这种处理方式可行。

private boolean isError=false;//网页是否加载失败

private class MyWebViewClient extends WebViewClient {

	@Override
	public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
		super.onReceivedError(view, errorCode, description, failingUrl);
		initNoMsgLayout(view);
		isError = true;
	}

	/** 延迟加载网页出错时展示的布局 */
	private void initNoMsgLayout(WebView view) {
		ViewStub stub = (ViewStub) findViewById(R.id.vs_nomsg_layout);
		if (stub != null) {// ViewStub在调用inflate()后会从页面中移除,再次findViewById时返回null
			ll_nomsg_container = stub.inflate();
		} else {
			ll_nomsg_container.setVisibility(View.VISIBLE);
		}
		view.setVisibility(View.GONE);
	}
}
private class MyWebChromeClient extends WebChromeClient {
	@Override
	public void onProgressChanged(WebView view, int newProgress) {
		if (newProgress == 100) {
			progress_bar.setProgress(newProgress);
			progress_bar.setVisibility(View.GONE);
			if (!isError) {
				if (ll_nomsg_container != null) {
					ll_nomsg_container.setVisibility(View.GONE);
				}
				view.setVisibility(View.VISIBLE);
			}
			isError = false;
		} else {
			if (progress_bar.getVisibility() == View.GONE)
				progress_bar.setVisibility(View.VISIBLE);
				progress_bar.setProgress(newProgress);
			}
		super.onProgressChanged(view, newProgress);
	}
}

    (2)自定义错误网页,将其放在assets文件夹中,在网页出错时加载该错误网页。在onReceivedError()方法中加载本地错误页面:

private class MyWebViewClient extends WebViewClient {

	@Override
	public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
		super.onReceivedError(view, errorCode, description, failingUrl);
		webview.loadUrl("file:///android_asset/error.html"); 
	}
}

     当然,如果自定义的错误页面error.html页面中有js的调用,还得针对WebVew设置相关属性:

webview.getSettings().setJavaScriptEnabled(true);//支持js调用
webview.getSettings().setUseWideViewPort(true);//页面展示时缩放到合适大小

     虽然此方法使用简单,但是如果网页中有链接跳转的话,想维护前进后退以及刷新功能的话,就得做额外处理了,因为此方法的处理将错误页面的加载也放到了前进后退中。找了好久WebView相关的API也没找到添加和移除浏览历史的方法,最后写了这么一个笨方法:

@Override
public void onClick(View v) {
	switch (v.getId()) {
	case R.id.tv_title_content:// 返回
		if (webview != null) {
			WebBackForwardList copyBackForwardList = webview.copyBackForwardList();
			int currentIndex = copyBackForwardList.getCurrentIndex();
			if (currentIndex > 0) {
				String currUrl = copyBackForwardList.getCurrentItem().getUrl();
				if (currUrl.contains("file:///")) {
					currUrl = copyBackForwardList.getItemAtIndex(currentIndex - 1).getUrl();
					currentIndex--;
				}
				int backStep = 1;// 累计需要后退的步数
				for (int i = currentIndex - 1; i >= 0; i--) {
					String backUrl = copyBackForwardList.getItemAtIndex(i).getUrl();
					if (backUrl.contains("file:///") || backUrl.equals(currUrl)) {// 当为错误页面或与当前页面一样时,累加需跳转的步数
						backStep++;
						continue;
					}
					if (webview.canGoBackOrForward(-backStep)) {
						webview.goBackOrForward(-backStep);
					} else {
						finish();
					}
					break;
				}
				if (backStep > currentIndex) {
					finish();
				}
			} else {
				finish();
			}
		} else {
			finish();
		}
		break;
	case R.id.tv_first_operator:// 刷新
		if (webview != null) {
			WebBackForwardList copyBackForwardList = webview.copyBackForwardList();
			WebHistoryItem currentItem = copyBackForwardList.getCurrentItem();
			if (currentItem != null) {
				String currUrl = currentItem.getUrl();
				if (currUrl.contains("file:///") && webview.canGoBack()) {
					// 加载网页出错时加载了一次本地的错误页面,所以如果当前展示的是错误页面,则执行后退操作即可回到上次加载的页面
					webview.goBack();
					WebBackForwardList copyBackForwardList2 = webview.copyBackForwardList();
					WebHistoryItem currentItem2 = copyBackForwardList2.getCurrentItem();
					if (currentItem2 != null) {// 因为此处的刷新操作不会导致WebBackForwardList中两个及以上的错误页面连续,所以回退一次之后一定是可用链接
						webview.loadUrl(currentItem2.getUrl());
					}
					return;
				} else {
					webview.reload();
				}
			}
		}
		break;
	}
}


5、关于有重定向页面时执行goback()方法无法正常后退的问题,当利用WebView加载页面时,如果加载的页面又重定向到了另外一个页面,造成页面无法利用goback()方法执行后退。其实这不是WebView的bug,而是我们在重写方法的时候不小心给自己设的一个陷阱。当我们为了防止点击页面中的链接而跳转到系统自带的浏览器时要重写WebViewClient中的shouldOverrideUrlLoading()方法,网上大部分的资料是这样的:

webView.setWebViewClient(new WebViewClient() {

	@Override
	public boolean shouldOverrideUrlLoading(WebView view, String url) {
		view.loadUrl(url);
		return true;
	}

});

 注意该函数的返回值,此函数默认是返回false的return super.shouldOverrideUrlLoading(view, url);,所以很多人想当然的认为返回true就可以限制到自己的WebView页了,殊不知这个返回值正是导致有重定向页面时无法正常后退的原因,改为返回false即可解决此问题。其实如果单单只是想将页面中的跳转限制到自己的WebView中的话只需要做如下操作即可:

webview.setWebViewClient(new WebViewClient());

        为了更清楚的了解是怎么回事,查看了一下父类的shouldOverrideUrlLoading()方法,如下:

/**
     * Give the host application a chance to take over the control when a new
     * url is about to be loaded in the current WebView. If WebViewClient is not
     * provided, by default WebView will ask Activity Manager to choose the
     * proper handler for the url. If WebViewClient is provided, return true
     * means the host application handles the url, while return false means the
     * current WebView handles the url.
     * This method is not called for requests using the POST "method".
     *
     * @param view The WebView that is initiating the callback.
     * @param url The url to be loaded.
     * @return True if the host application wants to leave the current WebView
     *         and handle the url itself, otherwise return false.
     */
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        return false;
    }
从方法的注释中我们可以看到,在一个新的链接被加载时,会出现以下三种情况:
1、如果没有提供WebViewClient对象,即没有调用WebView的setWebViewClient(WebViewClient client)方法为其设置Client对象,则WebView会请求android系统的Activity管       理器去处理该url链接的加载,一般情况就是启动系统浏览器来加载该url;
2、如果提供了WebViewClient对象并且shouldOverrideUrlLoading()方法返回true,则表示该Url交由当前应用程序自己来处理,当前WebView不会再加载该Url;
3、如果提供了WebViewClient对象并且shouldOverrideUrlLoading()方法返回false,则表示该Url交由当前应用程序的当前WebView自己来处理。

通过该注释我们清楚的了解到只要我们为WebView设置了新的WebViewClient对象,该url链接的加载就会交由当前应用自己来处理,即设置以下一行代码即可:
webview.setWebViewClient(new WebViewClient());
至于限制链接在当前应用中加载之后的处理,就要根据需求来了,如果想要当前WebView继续加载该Url链接,那就返回false,如果想终止掉当前WebView对该Url链接的加载,就返回true。

6、WebView访问https页面时出现空白页的问题。
    当使用WebView访问某些ssl加密的url时,页面会出现空白的情况,而使用系统自带的浏览器打开时,会弹出确认证书的对话框。这是用于某些站点需要证书确认才能访问的缘故,简单的处理方法是忽略这步证书的确认:
webView.setWebViewClient(new WebViewClient(){

<span style="white-space:pre">	</span>@Override
	public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
		handler.proceed();
	}
});


版权声明:本文为博主原创文章,转载请注明出处:http://blog.csdn.net/biaobiao1217

相关文章推荐

android webView onPageFinish调用多次??(未解决)

在WebView的应用中,可以使用WebViewClient监听WebView的内容【加载】事件,比如onPageFinished、onPageStarted等。但是即使onPageFinished触...

android WebView(五)WebChromeClient

WebView诸如获取页面的title、响应js中的alert、获取页面的加载进度等都可以通过设置WebChromeClient来实现。 首先来看一下设置WebChromeClient的代码: web...

Android WebView问题汇总以及解决方法

Android WebView常见问题解决方案汇总: 1、Android webview背景设置为透明无效 webview是一个使用方便、功能强大的控件,但由于webview的背景颜色默认是白色,在一...

解决webview在小米手机显示

1,首先就是配置问题, webSettings.setUseWideViewPort(true); webSettings.setLoadWithOverviewMode(true);...

Android WebView使用经验总结

接触WebView这么久,也积累了不少相关知识点,今天跟大家分享一下,希望对大家有帮助。 一.常用API setAllowFileAccess 启用或禁止WebView访问文件数据 setBloc...

浅谈WebView的使用

WebView是Android中一个非常实用的组件,它和Safai、Chrome一样都是基于Webkit网页渲染引擎,可以通过加载HTML数据的方式便捷地展现软件的界面。使用WebView开发软件有一...
  • liuhe688
  • liuhe688
  • 2011年06月16日 18:49
  • 34171

android WebView 浏览历史管理前进和后退

通过设置WebViewClient,可以设置在网页开始下载和下载完毕后要做的操作。如在下载时进度条和下载时标题显示文字可以在这设置,下载后设置title为网页标题也要在这设置。开户前进后退等功能也要在...
  • jdsjlzx
  • jdsjlzx
  • 2012年08月03日 14:05
  • 13597

关于使用webview的一些坑和经验总结

WebView是基于webkit引擎展现web页面的控件,而且越来越多项目在使用hybrid模式,因此我们在日常开发中不可避免的回合WebView打交道,也会碰到各种各样的问题,有可能是手机系统版本问...

WebView问题及解决方案

随着h5的普及, webveiw使用度越来越高,作为安卓的最复杂的控件,使用时会遇到一些头疼的bug,总结如下 当拿到webview的时候,我们往往需要根据情况做一些配置,这个地方处理不到经常会出现...

webview常见问题集锦

转载请标明出处一片枫叶的专栏本文中我们将介绍一下Android中webview在使用过程中会遇到的一些问题。这些问题主要是webview在使用过程中我已经趟过的坑,希望通过这篇文章的介绍能够帮助大家更...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:WebView中常见问题总结
举报原因:
原因补充:

(最多只允许输入30个字)