xiaoguozi's Blog
Pay it forword - 我并不觉的自豪,我所尝试的事情都失败了······习惯原本生活的人不容易改变,就算现状很糟,他们也很难改变,在过程中,他们还是放弃了······他们一放弃,大家就都是输家······让爱传出去,很困难,也无法预料,人们需要更细心的观察别人,要随时注意才能保护别人,因为他们未必知道自己要什么·····

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

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函数

 /**
     * Get the InputStream for an Android resource
     * There are three different kinds of android resources:
     * - file:///android_res
     * - file:///android_asset
     * - content://
     * @param url The url to load.
     * @return An InputStream to the android resource
     */

这个函数会对几种特殊的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.

http://blog.csdn.net/hxwwf/article/details/7281318
posted on 2013-02-22 15:07 小果子 阅读(1610) 评论(0)  编辑 收藏 引用 所属分类: 学习笔记Android & Ios

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理