[Android杂记]关于WebView的执行线程

2,330 阅读2分钟

【前言】最近在写 WebView 相关的一些代码,其中会有两个 WebView 同时加载网页的场景。由于会有一些代码可能会有并发问题,涉及到加锁的操作,所以对 WebView 的回调线程的代码做了一些查看,在这里随便分享一下。

一、多个 WebView 的同一回调方法的线程一致

对 WebView A 和 WebView B 的 shouldInterceptRequest() 都使用断点,同时加载网页,可观察到它们的回调线程都是 "Thread-7"。

image.png

所以,这个特点打消了我对于并发的顾虑,并说明了即使两个 WebView 同时加载页面,它们的回调方法也是在同一个线程中执行的。如果在 WebView A 的回调方法中阻塞住,那 WebView B 的回调方法也会阻塞住。

二、进一步探究 WebView 的执行线程

多个 WebView 回调方法的线程一致,这个只是碰巧,还是特定系统如此,还是源码定义,怀着这样的疑问,笔者去查看了一个源码,看 WebView 是怎么处理的。

1. 查看其调用栈

image.png

根据调用栈去查看 AwContents,找到其内部类:BackgroundThreadClientImpl。这时可以清晰地看到其代码:

private class BackgroundThreadClientImpl extends AwContentsBackgroundThreadClient {
        // All methods are called on the background thread.
        @Override
        public AwWebResourceResponse shouldInterceptRequest(
                AwContentsClient.AwWebResourceRequest request) {
            String url = request.url;
            AwWebResourceResponse awWebResourceResponse;
            ...
            return awWebResourceResponse;
        }
    }

上面的注释清楚地写着 // All methods are called on the background thread.,说明 WebView 的 shouldInterceptRequest() 回调都是从它的 background thread 调用的。除此之外,也可以看到还有一个 IoThreadClientImpl 的内部类,即使用 io thread 执行的类,里面的方法包括 shouldBlockContentUrls(),onDownloadStart() 等。

这里可以知道,WebView 中的回调方法,是会统计分发到特定线程执行。

2. WebView 的执行线程是如何分发的

看到这里,笔者会有一个疑问,shouldInterceptRequest() 是从哪里调用的,是否 WebView 内部有一个静态的线程池,在调用 shouldInterceptRequest() 时会切换到 background 线程。带着这个疑问,继续查看代码。

在 AwContents 中,BackgroundThreadClientImpl 成员变量是由 IoThreadClientImpl 成员变量持有的,调用 BackgroundThreadClientImpl 需要通过 IoThreadClientImpl,接下来看看谁会调用 IoThreadClientImpl。代码中把 IoThreadClientImpl 在 nativeSetJavaPeers() 中作为参数传入,而 nativeSetJavaPeers() 是个 native 方法,看来要看到 native 层的代码去了。

那 native 层中是怎么运行的呢,待续...