Android Browser App 源码分析(二)

接着分析browser中的首启动activity,通过AndroidManifest可以看出Browser初始化启动的Activity为BrowserActivity

<activity android:name="BrowserActivity" android:label="@string/application_name" android:launchMode="singleTask" android:alwaysRetainTaskState="true" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:theme="@style/BrowserTheme" android:windowSoftInputMode="adjustResize" >
            <intent-filter>
                <action android:name="android.speech.action.VOICE_SEARCH_RESULTS" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
            <!-- For these schemes were not particular MIME type has been supplied, we are a good candidate. -->
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="http" />
                <data android:scheme="https" />
                <data android:scheme="about" />
            </intent-filter>
            <!-- For these schemes where any of these particular MIME types have been supplied, we are a good candidate. -->
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.BROWSABLE" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="http" />
                <data android:scheme="https" />
                <data android:mimeType="text/html"/>
                <data android:mimeType="text/plain"/>
                <data android:mimeType="application/xhtml+xml"/>
                <data android:mimeType="application/vnd.wap.xhtml+xml"/>
            </intent-filter>
            <!-- Accept inbound NFC URLs at a low priority -->
            <intent-filter android:priority="-101">
                <action android:name="android.nfc.action.NDEF_DISCOVERED" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="http" />
                <data android:scheme="https" />
            </intent-filter>
            <!-- We are also the main entry point of the browser. -->
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.LAUNCHER" />
                <category android:name="android.intent.category.BROWSABLE" />
                <category android:name="android.intent.category.APP_BROWSER" />
            </intent-filter>
            <!-- The maps app is a much better experience, so it's not worth having this at all... especially for a demo! <intent-filter android:label="Map In Browser"> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="vnd.android.cursor.item/postal-address" /> </intent-filter> -->
            <intent-filter>
                <action android:name="android.intent.action.WEB_SEARCH" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="" />
                <data android:scheme="http" />
                <data android:scheme="https" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.MEDIA_SEARCH" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.SEARCH" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
            <meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />
        </activity>

1、BrowserActivity定义的launchMode为singleTask。
singleTask的作用是:任务栈中保持只有一个自己的实例。如果任务栈存在这个实例,且在栈顶,则直接启动这个实例,无需创建新的activity实例
如果存在这个实例,但是不在栈顶的位置上,则销毁此activity实例以上的所有activity实例
详细介绍可参考,转载请注明:
http://www.cnblogs.com/xiaoQLu/archive/2011/09/29/2195742.html
http://blog.csdn.net/wdaming1986/article/details/7304191

2.BrowserActivity定义了许多intent-filter来过滤intent,例如通过intent-filter来拦截http/https 协议的请求,以及内容类型为text/html、text/plain、application/xhtml+xml、application/vnd.wap.xhtml+xml的请求。

接下来分析BrowserActivity.java,Activity启动之后,首先会执行onCreate 方法

public void onCreate(Bundle icicle) {
    if (LOGV_ENABLED) {
        Log.v(LOGTAG, this + " onStart, has state: "
                + (icicle == null ? "false" : "true"));
    }
    super.onCreate(icicle);

    if (shouldIgnoreIntents()) {
        finish();
        return;
    }

    // If this was a web search request, pass it on to the default web
    // search provider and finish this activity.
    if (IntentHandler.handleWebSearchIntent(this, null, getIntent())) {
        finish();
        return;
    }
    mController = createController();

    Intent intent = (icicle == null) ? getIntent() : null;
    mController.start(intent);
}

首先看shouldIgnoreIntents() 方法:

private boolean shouldIgnoreIntents() {
       // Only process intents if the screen is on and the device is unlocked
       // aka, if we will be user-visible
       if (mKeyguardManager == null) {
           mKeyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
       }
       if (mPowerManager == null) {
           mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
       }
       boolean ignore = !mPowerManager.isScreenOn();
       ignore |= mKeyguardManager.inKeyguardRestrictedInputMode();
       if (LOGV_ENABLED) {
           Log.v(LOGTAG, "ignore intents: " + ignore);
       }
       return ignore;
}

如果当前屏幕变暗,或者处于锁屏状态,则忽略这次请求。

createController方法用来创建Controller核心控制器,Controller实现UiController接口

private Controller createController() {
      Controller controller = new Controller(this);
      boolean xlarge = isTablet(this);
      UI ui = null;
      if (xlarge) {
          ui = new XLargeUi(this, controller);
      } else {
          ui = new PhoneUi(this, controller);
      }
      controller.setUi(ui);
      return controller;
}

如果是平板,创建的UI实例为XLargeUi,如果不是平板,则创建的UI实例为PhoneUi,之后将创建的UI传递到Controller中,这块使用的设计模块是策略模式,在屏幕不同的版本时选用不同的策略,也就是不同的UI实例,就像volley初始化HttpStack那样

if (Build.VERSION.SDK_INT >= 9) {
    stack = new HurlStack();
} else {
    stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
}

整个BrowserActivity中所有的事件回调,都会委托Controller去执行,这样整个Activity的代码体积将会变得很小。开发模式很像大名鼎鼎的MVP模式,UI(V)保留着Controller(P)的引用,Controller(P)保留着UI(V)的引用,并且两者都是通过定义好的接口进行交互。

    原文作者:Android源码分析
    原文地址: https://blog.csdn.net/asdf812225572/article/details/51671339
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞