ShouldInterceptRequest WebViewClient shouldInterceptRequest WebViewClient shouldInterceptRequest WebViewClient shouldInterceptRequest WebViewClient shouldInterceptRequest
@Deprecated
public WebResourceResponse shouldInterceptRequest(WebView view,
String url) {
return null;
}
public WebResourceResponse shouldInterceptRequest(WebView view,
WebResourceRequest request) {
return shouldInterceptRequest(view, request.getUrl().toString());
}Copy the code
The second method is only supported in Android 5.0. Compared to the first method, we can get the request parameters other than the URL from the WebResourceRequest parameter of the second method, such as mineType. We can also see that if we don’t overload these two methods, Eventually both methods return NULL, with the second calling the first method. If null is returned, the WebView handles the loading of the resource. If not, we can load the resource from the network or local, encapsulate it in WebResourceResponse and return it. Finally, the WebView will use the returned resource. So we can use this method to host the download of Webview resources.
Let’s look at the method descriptions for these two methods.
Notify the host application of a resource request and allow the application to return the data. If the return value is null, the WebView will continue to load the resource as usual. Otherwise, the return response and data will be used. NOTE: This method is called on a thread other than the UI thread so clients should exercise caution when accessing private data or the view system.
We can see that this method is running on a non-UI thread, but there is an important issue that has not been highlighted above, which is that this method is executed on the same non-UI thread every time it is called (Chrome_FileThread), so this method blocks when multiple resources are concurrent. And generally the same HTML will inevitably have more than one resource.
A single thread requesting every resource on a page is unacceptable for page load speed, so let’s see where we can break through. Let’s start with WebResourceResponse and look at its constructor first
public WebResourceResponse(String mimeType, String encoding, InputStream data) {
mMimeType = mimeType;
mEncoding = encoding;
setData(data);
}
public WebResourceResponse(String mimeType, String encoding, int statusCode,
String reasonPhrase, Map<String, String> responseHeaders, InputStream data) {
this(mimeType, encoding, data);
setStatusCodeAndReasonPhrase(statusCode, reasonPhrase);
setResponseHeaders(responseHeaders);
}Copy the code
We proxy the InputStream member that points to the resource in WebResourceResponse by static proxy to see which thread the final WebView processes the resource data.
@Override public WebResourceResponse shouldInterceptRequest(WebView view, final String url) { Log.i(TAG, String.format("shouldInterceptRequest in thread: %s[%s] url: %s", Thread.currentThread().getName(), Thread.currentThread().getId() + "", url)); return new WebResourceResponse("", "utf-8", new InputStream() { private InputStream inputStream = null; @Override public int read() throws IOException { Log.i(TAG, String.format("Reading data in thread %s[%s] url %s ", Thread.currentThread().getName(), Thread.currentThread().getId(), url)); if (inputStream == null) { try { Request request = new Request.Builder() .url(url) .build(); Response response = okHttpClient.newCall(request).execute(); inputStream = response.body().byteStream(); } catch (Exception e) { Log.e(TAG, "Fail Reading WebResourceResponse url: " + url); } } if (inputStream == null) { return -1; } else { return inputStream.read(); } } @Override public void close() throws IOException { super.close(); if (inputStream ! = null) { inputStream.close(); }}}); }Copy the code
09-14 10:39:52. 482, 28644-28705 / com. Tencent. Webviewsample I/MainActivity: Reading data from Thread-4[11409] url is https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1505545242&di=8a65cd2cf3995201b8028f853f592c35&imgty pe=jpg&er=1&src=http%3A%2F%2Fh.hiphotos.baidu.com%2Fzhidao%2Fpic%2Fitem%2F060828381f30e9240ff2cd434c086e061d95f76a.jpg 09-14 10:39:52. 482, 28644-29235 / com. Tencent. Webviewsample I/MainActivity: Reading data from Thread-7[11421] url is https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1505545266&di=2eff701f8f336f6427bdd8a50321b016&imgty Pe=jpg&er=1&src=http%3A%2F%2Fscimg.jb51.net % 2 fallimg % 2 f160131%2 f14-1601311 a539c3. JPG 10:39:52 09-14, 482 28644-28721/com.tencent.webviewsample I/MainActivity: Reading data from Thread-6[11419] url is https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1505544739&di=aab230dbfbc901260fc148e6e87ab059&imgty pe=jpg&er=1&src=http%3A%2F%2Fimg3.redocn.com%2F20100521%2FRedocn_2010052023544076.jpgCopy the code
We can break out of the shouldInterceptRequest single-threaded execution problem by providing the WebResourceResponse InputStream member that points to the resource. A resource download is performed when the system reads the first word of the data stream.
We use the following to compare the speed of image loading between single thread and multi-thread
<! DOCTYPE html> <html> <head> <script> window.addEventListener('load', function(ev) { App.onLoad('onload'); // The Java layer registers the JavasciptInterface APP so that the 'load' callback determines that the image is loaded}); </script> </head> <body> <img onload='console.log(1)' src='https://rescdn.qqmail.com/zh_CN/htmledition/images/webp/logo/qqmail/qqmail_logo_default_35h206ff1.png' /> <img onload='console.log(3)' src='https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1505544739&di=aab230dbfbc901260fc148e6e87ab059& imgtype=jpg&er=1&src=http%3A%2F%2Fimg3.redocn.com%2F20100521%2FRedocn_2010052023544076.jpg' /> <img onload='console.log(4)' src='https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1505545111&di=2d4fc96817efd328d2865bf4ac37559e& imgtype=jpg&er=1&src=http%3A%2F%2Fimg1.pconline.com.cn%2Fpiclib%2F200812%2F22%2Fbatch%2F1%2F19891%2F1229912689801kpqtgqz pxq.jpg' /> <img onload='console.log(5)' src='https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1505545242&di=8a65cd2cf3995201b8028f853f592c35& imgtype=jpg&er=1&src=http%3A%2F%2Fh.hiphotos.baidu.com%2Fzhidao%2Fpic%2Fitem%2F060828381f30e9240ff2cd434c086e061d95f76a. jpg' /> <img onload='console.log(6)' src='https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1505545266&di=2eff701f8f336f6427bdd8a50321b016& imgtype=jpg&er=1&src=http%3A%2F%2Fscimg.jb51.net%2Fallimg%2F160131%2F14-1601311A539C3.jpg' /> <img onload='console.log(7)' src='https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1505545753&di=c72dc06135b35c589bf9fcfbce5ff7e1& imgtype=jpg&er=1&src=http%3A%2F%2Fimg2.niutuku.com%2Fdesk%2Fanime%2F4446%2F4446-8866.jpg' /> <img onload='console.log(8)' src='https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1505545753&di=c72dc06135b35c589bf9fcfbce5ff7e1& imgtype=jpg&er=1&src=http%3A%2F%2Fimg2.niutuku.com%2Fdesk%2Fanime%2F4446%2F4446-8866.jpg' /> <img onload='console.log(9)' src='https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1505545784&di=efb541bc5fe7807ea9097ebb5c21e756& imgtype=jpg&er=1&src=http%3A%2F%2Fscimg.jb51.net%2Fallimg%2F140404%2F10-140404220101L9.jpg' /> </body> </html>Copy the code
Finally, after several tests, the data are as follows
Number of tests (unit :ms) | 1 | 2 | 3 | 4 | 5 | 6 | 7 | … | On average, | |
---|---|---|---|---|---|---|---|---|---|---|
Single thread | 407 | 416 | 364 | 477 | 377 | 317 | 433 | … | 398.7 | |
multithreading | 298 | 275 | 256 | 255 | 258 | 307 | 306 | … | 279.2 |
The multithreaded approach is 30% faster than the single-threaded approach.
In conclusion, this author has introduced a simple but effective way to solve the concurrency problem when hosting WebView resource downloads.