浏览器探究——执行网页跳转

浏览器探究——执行网页跳转

Main线程中执行。

UrlInputView

控件UrlInputView执行OnEditorAction->finishInput

/**

*url/search input view

*handling suggestions

*/

public class UrlInputView extendsAutoCompleteTextView

implements OnEditorActionListener,

CompletionListener, OnItemClickListener, TextWatcher

由此可见,UrlInputView即输入网址的那个控件,该控件包括输入URL和执行搜索输入。

Controller

在经过UrlInputView的处理后,会调用Controller.handleNewIntent。

Controller是浏览器中最重要的类,作为整个浏览器的主控类。Controller中有IntentHandler,这里会调用IntentHandler.onNewIntent

IntentHandler

//Handle all browser related intents

这里对一些特殊的URL做处理这里还包含了一些debug信息,比如”about:debug.dom.file"这种形式的网址。如果是普通的url,不需要做特殊处理,则执行到最后执行Controller.loadUrlDataIn,即经过了IntentHandler后又回到了Controller。

Controller

/**

* Load UrlData into a Tab and update the title bar to reflect the new

* load. Call this instead ofUrlData.loadIn directly.

* @param t The Tab used to load.

* @param data The UrlData being loaded.

*/

经过简单的处理,会把要加载的url作为参数调用被显示的tab,即执行Tab.loadUrl。这样看来Controller还只是个桥梁的作用,把从UrlInputView得到的url,交给IntentHandler做处理,然后再把url交给Tab做实际的加载。

Tab

//Class for maintaining Tabs with a mainWebView and a subwindow.

Tab作为一个窗口的抽象概念而存在,对一个窗口的操作都需要通过Tab来进入。另外有个TabControl用来管理所有的Tab.

执行语句mMainView.loadUrl。这个mMainView是个WebView。从这终于进入了framework的webkit层了。

WebView

WebView作为Tab的核心控件,负责网页的真正的加载,显示等操作,是framework/webkit中最主要的类。通过Tab来找到WebView.

在WebView.loadUrl->WebView.loadUrlImpl中会向WebViewCore发消息,

WebViewCore

该类在一个独立的线程中运行,该类主要通过Message,Handler的机制在WebView与WebViewCore之间通讯的,这里WebView是在Main线程中,而WebViewCore是在单独的WebViewCoreThread线程中。WebViewCore是framework/webkit核心类,它在单独的线程中来接收消息,每个消息相当于一个请求的任务,而这个WebViewCore相当于一个服务,它在消息循环中不停的接收任务(消息),然后处理任务,然后再接收下一个任务(消息)。任务的执行很多是通过jni调用c层webkit来操作的。在c层webkit有webkit/Source/WebKit/android/jni/WebViewCore.cpp与该java层的WebViewCore对应。即这个WebViewCore是java层与c层的一个主要桥梁。

在WebView.loadUrlImpl在执行了mWebViewCore.sendMessage(EventHub.LOAD_URL, arg);则WebViewCore接收到LOAD_URL任务,执行对它的处理。

WebViewCore中有BrowserFrame成员

BrowserFrame

BrowserFrame extends Handler它也有很多JNI与C层的webkit的Webkit/Source/WebKit/android/jni/WebCoreFrameBridge.cpp对应。它用来处理页面的具体情况,即Frame,这个Frame是一个具体的页面的概念。

WebViewCore.loadUrl会调用BrowserFrame.loadUrl。BrowserFrame会调用到WebCoreFrameBridge.cpp的LoadUrl。

这里略去c层的处理部分。

WebCoreFrameBridge.cpp的LoadUrl执行后会执行到WebCoreFrameBridge.cpp的loadStarted,这里又会回调BrowserFrame.loadStarted函数。

/**

* native callback

* Indicates the beginning of a new load.

* This method will be called once for the main frame.

*/

即通过BrowserFrame的loadUrl在c层做处理后,又回调到BrowserFrame的loadStarted。

这里在理一下,主线程中有Tab,Tab里有WebView。即WebView也是运行在主线程的。而WebView里有WebViewCore,WebViewCore又是运行在一个单独的线程里的。

那么多个WebView是否就对应多个WebViewCore和多个WebViewCore线程呢?

看下WebView,WebView的构造函数中会mWebViewCore= new WebViewCore(context, this, mCallbackProxy, javaScriptInterfaces);创建了WebViewCore对象,即每个WebView都有个WebViewCore对象。但是WebViewCore中的WebCoreThread是一个静态的,即一个单例的。而这个WebCoreThread中运行的privatestatic Handler sWebCoreHandler;也是个静态的。

由此可见WebViewCore类本身就是个外壳,真正处理任务的是WebCoreThread及其里面的sWebCoreHandler,这个真正处理任务的是静态的,只有一份,WebViewCore这个外壳只是沟通webView与WebCoreThread的桥梁,相当于一个代理类。是WebCoreThread提供给外面的处理接口。

那么BrowserFrame呢?在WebViewCore的构造最后会发送一个INITIALIZE的消息给WebCoreThread,WebCoreThread接收到后会执行WebViewCore.initialize,这个函数会构造mrowserFrame。即每次构造WebViewCore时同样会构造一个BrowserFrame。但是为什么不在主线程中创建呢?一方面它是继承自Handler,这个Handler需要在WebViewCoreThread线程中运行,所以需要在该线程来创建。另一方面在它的构造中需要创建JWebCoreJavaBridge这个是C层的类,貌似这个类也需要在WebViewCoreThread线程中创建和销毁才行。

由上分析可知,WebView包含一个WebViewCore,WebViewCore包含一个BrowserFrame。多个WebViewCore共同对应唯一的一个WebCoreThread。WebViewCore只是个外壳,WebCoreThread作为任务的处理,WebCoreThread主要就是个大Handler不停的处理接收到的任务,WebCoreThread会调用很多jni来调用webkit接口,BrowserFrame也有很多jni来调用webkit接口。由他们的组成情况又可知WebCoreThread直接调的jni是多个WebView共同的,即不跟具体的WebView相关,而通过BrowserFrame调用的则跟一个具体的WebView相关了。

CallBackProxy

/**

*This class is a proxy class for handling WebCore -> UI thread messaging. All

*the callback functions are called from the WebCore thread and messages are

*posted to the UI thread for the actual client callback.

*/

/*

*This class is created in the UI thread so its handler and any private classes

*that extend Handler will operate in the UI thread.

*/

class CallbackProxy extends Handler {

另外还有个类CallBackProxy。它存在于WebView,WebViewCore,BrowserFrame中。在WebView构造函数中创建,并在WebViewCore和BrowserFrame构造函数中作为参数传入并赋值给它们内部的引用。可见CallBackProxy是WebViewCore和BrowserFrame向WebView回调的桥梁。

CallBackProxy是一个Handler,它在主线程中被创建,即WebViewCore和BrowserFrame会通过发消息的方式将需求传递到主线程的CallBackProxy中,CallBackProxy的事件处理循环会执行相应的处理。可见主线程中WebView通过WebViewCore发消息给WebViewCoreThread线程执行操作,WebViewCoreThread线程又会通过CallBackProxy回调消息给主线程执行处理。

再回到BrowserFrame.loadStarted处。

BrowserFrame.loadStarted会调用CallBackProxy.onPageStarted,CallBackProxy.onPageStarted中会给发PAGE_STARTED消息,主线程中的CallBackProxy的handleMessage会执行处理。在处理时会执行WebViewClient.onPageStarted。

WebViewClient

mWebViewClient本身只是提供一个接口基类,Tab中private finalWebViewClient mWebViewClient = new WebViewClient()

// WebViewClient implementation for themain WebView

//Set the WebViewClient that will receivevarious notifications and requests. This will replace the current handler.

这个WebViewClient会传给Tab中的WebView的CallbackProxy。这个WebViewClient会让CallbackProxy返回信息或回调处理给Tab。

回到WebViewClient.onPageStarted,这里做了一些判断处理后,调用WebViewController.onPageStarted。

WebViewController

//WebView aspect of the controller

public interface WebViewController

在Tab的构造时,WebViewController会作为参数传入,并设置给Tab。那么Tab中的WebViewController到底是什么?Tab是在TabController中创建的,而Tab构造时传入的是Controller。

public class Controller implementsWebViewController, UiController

由此可见Tab中的WebViewController其实就是对应Controller。只是通过WebViewController接口作为引用的。即Tab中只关心Controller的WebViewController接口部分。

这样就可以看出BrowserFrame通过消息与主线程中的CallbackProxy处理循环关联,CallbackProxy又通过WebViewClient与Tab关联,回调了Tab提供的接口,而Tab又通过WebViewController接口,调用了Controller这个核心类的函数。即调用到WebViewController.onPageStarted,也即是Controller.onPageStarted.

Controller.onPageStarted中一个主要的处理是

if (!mNetworkHandler.isNetworkUp()) {view.setNetworkAvailable(false);}这里判断网络是否是激活状态,如果不是激活状态则执行WebView.SetNetworkAvailable(Boolean networkUp)

/** * Inform WebView ofthe network state. This is used to set* the JavaScript property window.navigator.isOnline and * generates the online/offline event asspecified in HTML5, sec. 5.7.7 *@param networkUp boolean indicating if network is available */

该函数其实就是像WebViewCore发送SET_NETWORK_STATE消息,好吧,又回到了WebViewCoreThread线程了,处理的方式是直接BrowserFrame.sJavaBridge.setNetworkOnLine。这个函数是个jni函数,其调用的是c层JavaBridge的函数。这个jni函数主要就是通知c层WebCore网路状态已经变化,并把最新的网络状态告诉WebCore。

由此可见WebView.setNetworkAvailable还是个挺重要的函数,通过它才能告诉底层网络的状态。

那么额外看下网络状态如何获取并传递的,在loadUrl发起加载url这块判断了一次,即当无网络时主动通知一次。其他的呢?

在NetworkStateHandler中会注册一个BroadcastReceiver,该receiver会关注ConnectivityManager.CONNECTIVITY_ACTION广播,该广播是在网络发生连接变化时被发出,该receiver在接收到网络连接变化的广播后,会查询当前的连接情况,然后执行NetworkStarteHandler.onNetworkToggle,这个函数里面就会调用WebView.setNetworkAvailable,也即跟上述描述的那样,给WebViewCoreThread线程发消息,通知c层WebCore网络的最新状态。

这样就清楚了,网络广播时会通知C层最新状态,在执行loadUrl时,如果网络不可用也会通知C层网络最新状态。

这里先跨过Controller.onPageStarte的其他处理过程。此次任务处理完毕。

此时WebViewCoreThread线程中BrowserFrame仍然处于c层的LoadUrl中,此时的调用栈为:

BrowserFrame.nativeLoadUrl

BrowserFrame.loadUrl

WebViewCore.loadUrl

这里又会回调BrowserFrame.shouldInterceptRequest,它会调用BrowserFrame.inputStreamForAndroidResource函数

/**
*GettheInputStreamforanAndroidresource
*Therearethreedifferentkindsofandroidresources:
*-file:///android_res
*-file:///android_asset
*-content://
*@paramurlTheurltoload.
*@returnAnInputStreamtotheandroidresource
*/

这个函数会对几种特殊的url做不同的处理,当输入一个标准的http的url时,该函数不起什么作用。

BrowserFrame.shouldInterceptReques接下来会调用CallbackProxy.shouldInterceptRequest,看到调用CallbackProxy的函数,基本上就是要发消息给主线程让主线程去处理任务了,这里发送了LOAD_RESOURCE消息,主线程接收后执行WebViewClient.onLoadResource。回到BrowserFrame.nativeLoadUrl处,此时这个jni的函数终于执行完毕,也不再回调其他函数了,该函数完成,WebViewCoreThread线程执行完LoadUrl的处理。

当没有连接网络时,有个单独的线程会执行JWebCoreJavaBridge.signalServiceFuncPtrQueue这个JNI的回调函数,该回调函数会发FYBCPTR_MESSAGE消息给WebViewCoreThread线程,但处理函数是JWebCoreJavaBridge.handle,由此可见WebViewCoreThread线程不仅仅有一个Handler在处理事件.

JWebCoreJavaBridge

JWebCoreJavaBridge extends Handler 可见JWebCoreJavaBridge也是个Handler也是在WebViewCoreThread线程中运行的,只是发送消息的线程不是主线程,是另一个单独的线程,并且消息的发送来源是JNI的回调。

JWebCoreJavaBridge对应的JNI是webkit/Source/WebKit/android/jni/JavaBridge.cpp的函数。

JWebCoreJavaBridge处理FYBCPTR_MESSAGE消息时会调用一个JNI函数,在JNI函数里又会回调BrowserFrame.reportError。

又是跟上面类似的流程,BrowserFrame.reportError调用CallbackProxy.onReceiveError,这个CallbackProxy里会发消息REPORT_ERROR,然后主线程接收消息,执行WebViewClient.onReceivedError。

接着又是收到FUNCPTR_MESSAGE消息,调用nativeServiceFuncPtrQueue,但是这里回调了BrowserFrame.loadStarted,然后的处理流程跟上述的LoadUrl中调用BrowserFrame.loadStarted过程一样。

接着WebViewCoreThread线程又是收到FUNCPTR_MESSAGE消息,调用JWebCoreJavaBridge.nativeServiceFuncPtrQueue,WebViewCore.contentDraw被调用,该函数发送WEBKIT_DRAW,处理该消息会执行绘制的操作。

接着WebViewCoreThread线程中JWebCoreJavaBridge.handleMessage又被调用,还是FUNCPTR_MESSAGE消息,仍然是调用nativeServiceFuncPtrQueue。但此时BrowserFrame收到loadFinished的回调,发PAGE_FINISHED消息,主线程接收消息处理时会执行WebView.onPageFinished和WebViewClient.onFinished.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值