Android -- browser java 部分

        本文主要对browser 的java部分代码一个简单说明,主线基本上围绕着第一次打开 browser加载网页的流程展开, 同时顺便提了下App层几个主要类的关系。以便大家可以更快了解 browser的上层代码,然后腾出时间去关注 webkit部分代码。webkit部分代码可非常多哦。首先根据logcat 的日志信息或 brower应用的Androidmanifest.xml, 打开browser 第一个界面是 BrowserActivity.java。这里面代码不多,关注下 oncreate()里初始化动作就好了,同时在这里我们也先整理下一些类的关系。

 public void onCreate(Bundle icicle) {     
        super.onCreate(icicle);    
        if (IntentHandler.handleWebSearchIntent(this, null, getIntent())) {
            finish();
            return;
        }
        mController = new Controller(this, icicle == null);
        boolean xlarge = isTablet(this);
        if (xlarge) {
            mUi = new XLargeUi(this, mController);
        } else {
            mUi = new PhoneUi(this, mController);
        }
        mController.setUi(mUi);
        Bundle state = getIntent().getBundleExtra(EXTRA_STATE);
        if (state != null && icicle == null) {
            icicle = state;
        }
        mController.start(icicle, getIntent());   
        上面的代码做了下面几件事: 1、 New了一个controller 对象,

                                                             2、根据当前设备是 phone还是pad 初始化了 I, 

                                                              3. 把mUI传给 mController,让Controller 持有UI的引用以便后面可以操作 UI。

         再稍微往下看两步,看看 controller和UI 里面有什么。Controller的构造函数 :

  public Controller(Activity browser, boolean preloadCrashState) {
        mActivity = browser;
        mSettings = BrowserSettings.getInstance();
        mTabControl = new TabControl(this);
        mSettings.setController(this);
       ……….省略了无关代码  
        mFactory = new BrowserWebViewFactory(browser);
        ……..省略了无关代码  
 }
        这里有一个 Tabcontrol,用来管理Tab ,这个Tab是什么呢?这要看下前面 UI这个接口的实现了,UI接口的实现类是 BaseUI,phoneUI 和XlargerUI均继承于 BaseUI(这里是典型的面向对象设计 )。BaseUI 由Titlebar和 Tab两部分组成,Titlebar就是我们看到网址输入那部分,而 Tab就是下面的网页部分,在 Tab.java的代码中,我们是可以找到 webview对象的,可以理解为Tab把 webview包装了一层。再回到controller这个类,注意 controller是实现了webviewCotroller ,UiController接口的(注意tabcontroller可不是接口,它只是一个普通类),到这里有没有感觉 controller.java这个类好强大,借助Tabcontroller管理着一组 Tab,Tab 有webview的实例, controller再根据具体的Tab对象控制着每一个 webview。这家伙就是browser app层的一个总管啊,只要能获得 controller的引用,就可以完成界面 webview的控制。 类的关系先说到这,下面还是看打开网页的流程吧,接 OnCeate()里面mController.start(icicle, getIntent());  具体的代码如下

 void start(final Bundle icicle, final Intent intent) {
        boolean noCrashRecovery = intent.getBooleanExtra(NO_CRASH_RECOVERY, false);
        if (icicle != null || noCrashRecovery) {
            doStart(icicle, intent, false);
        } else {
            mCrashRecoveryHandler.startRecovery(intent);
        }
    }
       不管走哪个分支,最后还是会来到同一个类中的 doStart(final Bundle icicle, final Intent intent, final boolean fromCrash),在 doStart()里面的代码是我们关心的。 
GoogleAccountLogin.startLoginIfNeeded(mActivity,
new Runnable() {
     @Override public void run() {
     onPreloginFinished(icicle, intent, currentTabId, restoreIncognitoTabs,
                                fromCrash);  }  });  
      这里开一个线程去开始load网页内容,线程 start动作在startLoginIfNeeded ()这里面。去 onPreloginFinished里面看看吧,       

private void onPreloginFinished(Bundle icicle, Intent intent, long currentTabId,
            boolean restoreIncognitoTabs, boolean fromCrash) {
        //省略了暂时无关的代码
        if (currentTabId == -1) {         
            Tab t = null;
          if (urlData.isEmpty()) {
                t = openTabToHomePage();// 没有url就打开主页
          } else {
                t = openTab(urlData);// 打开传过来的 url
          }         
        } else {
        } 
    }
        顺着上面的代码跟踪几步就会发现后面的流程大同小异,不管是 openTabToHomePage还是openTab ,都会执行 createNewTab(),再执行loadUrl() 函数,而 loadUrl()最终起作用代码在Tab.java,下面的代码
    public void loadUrl(String url, Map headers) {
        if (mMainView != null) {
            mPageLoadProgress = INITIAL_PROGRESS;
            mInPageLoad = true;
            mCurrentState = new PageState(mContext, false, url, null);
            mWebViewController.onPageStarted(this, mMainView, null);
            mMainView.loadUrl(url, headers);
        }
    }
       mMainView是 webview的实例,所以到这里packages层的代码流程也就结束了,开始转入 framework层,毫无疑问webview.java肯定是这一层的核心的代码之一了。 来看看看Webview里的loadUrl ()方法。

    public void loadUrl(String url, Map additionalHttpHeaders) {
        checkThread();
        loadUrlImpl(url, additionalHttpHeaders);
    }

    private void loadUrlImpl(String url, Map extraHeaders) {
        switchOutDrawHistory();
        WebViewCore.GetUrlData arg = new WebViewCore.GetUrlData();
        arg.mUrl = url;
        arg.mExtraHeaders = extraHeaders;
        mWebViewCore.sendMessage(EventHub.LOAD_URL, arg);// 要注意这个 TAG。
        clearHelpers();
    }
        通过对上面TAG :EventHub.LOAD_URL的跟踪,可以发现代码已经来到 WebCoreView
         case LOAD_URL: {
              CookieManager.getInstance().waitForCookieOperationsToComplete();
              GetUrlData param = (GetUrlData) msg.obj;
              loadUrl(param.mUrl, param.mExtraHeaders);
              break;
         }
        那这里的loadUrl() 指向哪里呢,继续看很快可以找到,借助IDE工具理清这样的关系还是很快的。
    private void loadUrl(String url, Map extraHeaders) {
        if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, " CORE loadUrl " + url);
        mBrowserFrame.loadUrl(url, extraHeaders);
    }
        又出来个新变量mBrowserFrame,看下类型声明知道它是 BrowserFrame的实例,利用sourceInsight的跳转功能直接过去看看。

    public void loadUrl(String url, Map extraHeaders) {
        mLoadInitFromJava = true;
        if (URLUtil.isJavaScriptUrl(url)) {
               stringByEvaluatingJavaScriptFromString(
                    url.substring("javascript:".length()));
        } else {
            nativeLoadUrl(url, extraHeaders);
        }
        mLoadInitFromJava = false;
    }
       这里看到nativeLoadUrl ,看来要用到 JNI的知识了,下面这句话告诉我们接下来去哪,

    { "nativeLoadUrl", "(Ljava/lang/String;Ljava/util/Map;)V", (void*) LoadUrl },
       WebCoreFrameBridge.cpp (external\webkit\source\webkit\android\jni)里的loadUrl 函数,到这里算是把请求送 c层的webkit 了,目前也只跟到这里,后面就是等回调消息,除了前面提到的类还会涉及到 CallBackproxy.java,这个家伙是一个非常重要的桥梁,我们的 BrowserFrame会通过CallbackProxy 向主线程发消息,总之它是比较重要的,对于webkit部分的代码理解目前还处在迷糊状态,不知道从哪里下手,所以这后面流程还有待进一步挖掘,同时求高手指点一二。

        那么到这里小结一下,对 framework层的browser ,我们要重点关注 webview.java、CallBackproxy.java 、BrowserFrame.java、 WebCoreFrameBridge这几个类,其它类暂时还没注意到,肯定还有漏网之鱼,不过先把这几个主线类抓住再说,细节的东西慢慢来。

       本文的故事也到此结束,要说明的上面的只是对android原生浏览器 java部分代码调用流程的简单分析,事实上应用层代码功能更偏向对网页( webview)的管理和显示,与webkit本身没有太多的联系,如果只是对 webkit感兴趣,只看下webkit部分是完全可以的,当然它的代码规模还比较大,要花些时间去理解。


       PS:在目前的 browser设置中有个实验室选项,那个有快速控制选项,打开它会开启圆形的菜单功能,好像从android 3.0的版本开始就这个功能了,对应的代码实现是以 Pie开头的那些类代码,这个应该算是个动态控制的,不是固定坐标那种,有兴趣的可以看看。

你可能感兴趣的:(Android的原生应用分析)