WebView作为承载网页的控件,在网页显示的过程中会产生一些事件,并回调给我们的应用程序,以便我们在网页加载过程中做应用程序想处理的事情。比如说客户端需要显示网页加载的进度、网页加载发生错误等等事件。
由于现在项目中部分页面图片之类的资源很多,导致数据传输量很大,一定概率会出现空白页面,也就是资源加载超时导致的。
为了解决这个问题,目前解决的思路是:通过计时器来控制同一个资源是否超时加载,如果超过时限,可以控制重新再加载或者提示错误之类的显示。
代码如下:
1.webView 配置设置
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
webView.getSettings().setLoadsImagesAutomatically(true);
webView.getSettings().setAllowFileAccess(true);资源加载超时操作
webView.getSettings().setAllowFileAccessFromFileURLs(true);
webView.getSettings().setTextSize(WebSettings.TextSize.NORMAL);
webView.getSettings().setDomStorageEnabled(true);
webView.getSettings().setDatabaseEnabled(true);
webView.getSettings().setAppCacheEnabled(true);
webView.getSettings().setGeolocationEnabled(true);
webView.getSettings().setBlockNetworkImage(true);
webView.getSettings().setAppCacheMaxSize(5 * 1048576);
webView.clearCache(true);
webView.setWebChromeClient(new WebChromeClient() {
2.webView 配置缓存容量 (非必须设置项)
//
通知应用程序webview内核web sql 数据库超出配额,请求是否扩大数据库磁盘配额。默认行为是不会增加数据库配额。
@Override
public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota,
long estimatedSize, long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
quotaUpdater.updateQuota(estimatedSize * 2);
}
//扩充缓存的容量
@Override
public void onReachedMaxAppCacheSize(long spaceNeeded, long totalUsedQuota, QuotaUpdater quotaUpdater) {
quotaUpdater.updateQuota(spaceNeeded * 2);
}
});
3.webView 网页中超链接按钮的响应
//对网页中超链接按钮的响应。当按下某个连接时WebViewClient会调用这个方法,并传递参数:按下的url。
// 设置Web视图
webView.setWebViewClient(new WebViewClient(){
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.startsWith(WebView.SCHEME_TEL)) { //
try {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse(url));
startActivity(intent);
} catch (android.content.ActivityNotFoundException e) {
DLog.e("markdayinfo", "Error dialing " + url + ": " + e.toString());
}
else if (url.startsWith(WebView.SCHEME_MAILTO)) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
startActivity(intent);
} catch (android.content.ActivityNotFoundException e) {
DLog.e("markdayinfo", "Error sending email " + url + ": " + e.toString());
}
}
// If sms:5551212?body=This is the message
else if (url.startsWith("sms:")) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
// Get address
String address = null;
int parmIndex = url.indexOf('?');
if (parmIndex == -1) {
address = url.substring(4);
}
else {
address = url.substring(4, parmIndex);
// If body, then set sms body
Uri uri = Uri.parse(url);
String query = uri.getQuery();
if (query != null) {
if (query.startsWith("body=")) {
intent.putExtra("sms_body", query.substring(5));
}
}
}
intent.setData(Uri.parse("sms:" + address));
intent.putExtra("address", address);
intent.setType("vnd.android-dir/mms-sms");
startActivity(intent);
} catch (android.content.ActivityNotFoundException e) {
DLog.e("markdayinfo", "Error sending sms " + url + ":" + e.toString());
}
}
// All else
else {
if ((url.startsWith("file://") || url.startsWith("http://") || url.startsWith("https://")) && !url.endsWith(".apk")) {
//This will fix iFrames
view.loadUrl(url);
}
// If not our application, let default viewer handle
else {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
startActivity(intent);
} catch (android.content.ActivityNotFoundException e) {
DLog.e("markdayinfo", "Error loading url " + url + ":" + e.toString());
}
}
}
return true;
//1、 默认返回:return super.shouldOverrideUrlLoading(view, url); 这个返回的方法会调用父类方法,也就是跳转至手机浏览器,平时写 webview一般都在方法里面写 webView.loadUrl(url); 然后把这 个返回值改成下面的false。
2、返回: return true; webview处理url是根据程序来执行的。
3、返回: return false; webview处理url是在webview内部执行。
}
4.webView 页面加载 超时操作
private String startUrl;
private Timer timer;
private boolean isReload;
//在加载页面资源时会调用,每一个资源(比如图片)的加载都会调用一次(JS CSS 图片加载都需要调用)
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
DLog.e("markdayinfo", "onPageStarted url:" + url);
startUrl = url;
isReload = false;
super.onPageStarted(view, url, favicon);
}
//加载每个资源 都需要调用。比较start的url和load的url 是否一样 来确定该资源加载时间 ,从而确定是否超时 以及后续操作
@Override
public void onLoadResource(WebView view, String url) {
DLog.e("markdayinfo", "onLoadResource url:" + url);
if (startUrl != null && !startUrl.equals(url)) {
stopTimer();
}
if (startUrl != null && startUrl.equals(url)) {
startTimer();
}
super.onLoadResource(view, url);
}
public void onPageFinished(WebView view, String url) {
DLog.e("markdayinfo", "onPageFinished");
stopTimer();
if (isReceivedError) {
return;
}
webView.getSettings().setBlockNetworkImage(false);
if (!isReload) {
if (webView.getVisibility() == View.GONE) {
webView.setVisibility(View.VISIBLE);
}
progressBar.setVisibility(View.GONE);
}
super.onPageFinished(view, url);
}
@Override
public void onReceivedError(WebView view, int errorCode,
String description, String failingUrl) {
DLog.e("markdayinfo", "onReceivedError");
stopTimer();
isReceivedError = true;
showError();
super.onReceivedError(view, errorCode, description, failingUrl);
}
//计时器 计时 加载每个资源 的时间 (超时操作)
private void startTimer() {
DLog.e("markdayinfo", "startTimer");
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
DLog.i("markdayinfo", "timerTask reload");
stopTimer();
isReload = true;
mHandler.sendEmptyMessage(2);
}
};
if (timer != null) {
timer.cancel();
}
timer = new Timer();
timer.schedule(timerTask, 1500);
}
private void stopTimer() {
DLog.e("markdayinfo", "stopTimer");
startUrl = null;
if (timer != null) {
timer.cancel();
timer.purge();
timer = null;
}
}
});
webView.addJavascriptInterface(this, "control");
progressBar.setVisibility(View.VISIBLE);
// mHandler.sendEmptyMessage(1);
}
PS:目前处理方法是这个,如果大家有什么更好的方法可以分享一下。谢谢!