探究WebView getContentHeight的内部实现看看是否需要进行额外计算
先从WebView入手
WebView.java
/**
* Gets the height of the HTML content.
*
* @return the height of the HTML content
*/
@ViewDebug.ExportedProperty(category = "webview")
public int getContentHeight() {
checkThread();
return mProvider.getContentHeight();
}
再找mProvider的实现
WebView.java
private void ensureProviderCreated() {
checkThread();
if (mProvider == null) {
// As this can get called during the base class constructor chain, pass the minimum
// number of dependencies here; the rest are deferred to init().
mProvider = getFactory().createWebView(this, new PrivateAccess());
}
}
getFactory()是关键
WebView.java
private static WebViewFactoryProvider getFactory() {
return WebViewFactory.getProvider();
}
查看WebViewFactory.getProvider(),直接看return
WebViewFactory.java
static WebViewFactoryProvider getProvider() {
//...
if (sProviderInstance != null) return sProviderInstance;
//...
try {
Class<WebViewFactoryProvider> providerClass = getProviderClass();
Method staticFactory = null;
try {
staticFactory = providerClass.getMethod(
CHROMIUM_WEBVIEW_FACTORY_METHOD, WebViewDelegate.class);
} catch (Exception e) {
if (DEBUG) {
Log.w(LOGTAG, "error instantiating provider with static factory method", e);
}
}
//...
try {
sProviderInstance = (WebViewFactoryProvider)
staticFactory.invoke(null, new WebViewDelegate());
if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance);
return sProviderInstance;
} catch (Exception e) {
//...
}
用到了反射,关键的getProviderClass(),也是直接看return
WebViewFactory.java
private static Class<WebViewFactoryProvider> getProviderClass() {
//...
try {
return getWebViewProviderClass(clazzLoader);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
//...
try {
return (Class<WebViewFactoryProvider>) Class.forName(NULL_WEBVIEW_FACTORY);
} catch (ClassNotFoundException e2) {
// Ignore.
}
//...
}
第二个return可以不用关心,因为有null,关注第一个return
WebViewFactory.java
/**
* @hide
*/
public static Class<WebViewFactoryProvider> getWebViewProviderClass(ClassLoader clazzLoader)
throws ClassNotFoundException {
return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY,
true, clazzLoader);
}
隐藏方法,看看CHROMIUM_WEBVIEW_FACTORY是什么东东
WebViewFactory.java
/** @hide */
private static final String CHROMIUM_WEBVIEW_FACTORY =
"com.android.webview.chromium.WebViewChromiumFactoryProviderForO";
OK,反射了这个类,去sdk source里找找
...
找啊找
...
发现在android-19,android-20,android-22里找到,高版本的都是null实现
随便找个android-22吧,路径如下:
android-sdk\sources\android-22\com\android\webview\chromium\WebViewChromiumFactoryProvider.java
回到上面
getProviderClass()完毕,反射出WebViewChromiumFactoryProvider实例,就可以执行其createWebView()方法了
WebViewChromiumFactoryProvider.java
@Override
public WebViewProvider createWebView(WebView webView, WebView.PrivateAccess privateAccess) {
WebViewChromium wvc = new WebViewChromium(this, webView, privateAccess);
synchronized (mLock) {
if (mWebViewsToStart != null) {
mWebViewsToStart.add(new WeakReference<WebViewChromium>(wvc));
}
}
return wvc;
}
OK 真正的实现找到了--->WebViewChromium.java,并且在同目录下
至此,WebView的傀儡 WebViewProvider mProvider已揭开真面目
下一步肯定是不忘初心,看看getContentHeight()的实现啦
WebViewChromiumFactoryProvider.java
@Override
public int getContentHeight() {
if (mAwContents == null) return 0;
// No checkThread() as it is mostly thread safe (workaround for b/10594869).
return mAwContents.getContentHeightCss();
}
又是桥接其他类来实现,AwContents.java,在 org.chromium.android_webview.AwContents;
AwContents提供的不是WebView的API,所以,需要一层桥接部分,将AwContents桥接到WebView,这就是图中的桥接模块,该模块位于Android源代码中的frameworks/webview/chromium/java/com/android/webview/chromium/目录下,WebViewChromium和WebViewChromiumFactory类作为WebView的具体实现,依赖于Chromium项目的AwContents模块。
github clone 一个Chromium项目看看
https://android.googlesource.com/platform/external/chromium_org
找啊找
在\chromium_org\android_webview\java\src\org\chromium\android_webview目录下找到AwContents.java
ok 查看其内部实现即可
AwContents.java
public int getContentHeightCss() {
return (int) Math.ceil(mContentHeightDip);
}
这里可以看出直接返回成员变量,未进行计算
那这个成员变量赋值在哪
AwContents.java
@CalledByNative
private void updateScrollState(int maxContainerViewScrollOffsetX,
int maxContainerViewScrollOffsetY, int contentWidthDip, int contentHeightDip,
float pageScaleFactor, float minPageScaleFactor, float maxPageScaleFactor) {
mContentWidthDip = contentWidthDip;
mContentHeightDip = contentHeightDip;
mScrollOffsetManager.setMaxScrollOffset(maxContainerViewScrollOffsetX,
maxContainerViewScrollOffsetY);
setPageScaleFactorAndLimits(pageScaleFactor, minPageScaleFactor, maxPageScaleFactor);
}
在这里赋值,可以根据注解@CalledByNative看出是Native层主动回调出来进行设置。
(也可在该实现中查看其它webview操作的实现。)
所以得到了想要的答案。
参考:
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1106/1921.htmlhttps://android.googlesource.com/platform/external/chromium_org
网友评论