Android--browser java部分

7530 ワード

本文は主に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、新しいコントロールオブジェクト、
                                                             2、現在のデバイスがphoneかpadかによってIを初期化し、 
                                                              3.mUIをmControllerに渡し、後でUIを操作できるようにControllerに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);
        ……..         
 }
        ここにTabを管理するTabcontrolがありますが、このTabは何ですか?これは、前のUIというインタフェースの実装を見ると、UIインタフェースの実装クラスはBaseUIであり、phoneUIとXlargerUIはBaseUI(ここでは典型的なオブジェクト向け設計)に継承されている.BaseUIはTitlebarとTabの2つの部分から構成されており、Titlebarは私たちがウェブサイトを見て入力した部分であり、Tabは次のページ部分であり、Tab.javaのコードの中で、私たちはwebviewオブジェクトを見つけることができ、Tabがwebviewを1層包装したと理解できる.またcontrollerというクラスに戻って、controllerはwebviewCotrollerを実現したことに注意して、UiControllerインタフェースの(tabcontrollerはインタフェースではありませんて、それはただ1つの普通のクラスです)、ここまでcontroller.javaというクラスがとても強くて、Tabcontrollerを借りてTabのグループを管理して、Tabはwebviewの実例があって、コントローラはさらに具体的なTabオブジェクトに基づいて各webviewを制御している.こいつはbrowser app層の総管だろう.controllerの参照さえ得られれば、インタフェースのwebviewの制御を完了することができる.クラスの関係はまずこれについて、次はやはりホームページを開く流れを見て、OnCeate()の中のmControl.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<String, String> 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<String, String> additionalHttpHeaders) {
        checkThread();
        loadUrlImpl(url, additionalHttpHeaders);
    }

    private void loadUrlImpl(String url, Map<String, String> 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<String, String> 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<String, String> 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(externalwebkitsourcewebkitandroidjni)の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で始まるクラスコードです.これは動的制御で、固定座標のようなものではありません.興味のあるものは見てください.