1. 程式人生 > >隱式啟動Activity

隱式啟動Activity

1)Aciton只要能匹配到其中一個字串就可以

2)category  假如Activity如下宣告

<activity android:name=".ActivitySecond">
                <intent-filter>
                        <action android:name="second"></action>
                    <category android:name="android.intent.category.DEFAULT"/>
                    <category android:name="a"></category>
                    <category android:name="b"></category>
                    <category android:name="c"></category>
                    <category android:name="d"></category>
                </intent-filter>
        </activity>

我把這些category看成一個集合{a,b,c,d},只要是Intent的category是它的子集{a,c}{c,d}那麼就可以成功啟動
  Intent intent = new Intent();
                intent.setAction("second");
                intent.addCategory("a");
                startActivity(intent);

但是形如下面的不可以
 Intent intent = new Intent();
                intent.setAction("second");
                intent.addCategory("a");
                intent.addCategory("e");
                startActivity(intent);

但是我如果把

 <category android:name="android.intent.category.DEFAULT"/>

去掉之後,是不能成功啟動的,我去查了一些也沒弄明白為啥? 

只好去看原始碼,根據的Activity的啟動過程開始了我的分析,下面是執行流程

1、   Activity.java
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options)


2、Instrumentation.java
public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity target,
            Intent intent, int requestCode, Bundle options)


3、ActivityManagerService.java

final int startActivity(Intent intent, ActivityStackSupervisor.ActivityContainer container)


4、ActivityStarter.java
 final int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, IActivityManager.WaitResult outResult, Configuration config,
            Bundle bOptions, boolean ignoreTargetSecurity, int userId,
            IActivityContainer iContainer, TaskRecord inTask)


注意這裡有一句話
ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);


5、ActivityStackSupervisor.java
 ResolveInfo resolveIntent(Intent intent, String resolvedType, int userId, int flags) {
        try {
            return AppGlobals.getPackageManager().resolveIntent(intent, resolvedType,
                    PackageManager.MATCH_DEFAULT_ONLY | flags
                    | ActivityManagerService.STOCK_PM_FLAGS, userId);
        } catch (RemoteException e) {
        }
        return null;
    }


給這個flags 添加了一個
PackageManager.MATCH_DEFAULT_ONLY 
然後呼叫了另一個方法
6、PackageManagerService.java


  public ResolveInfo resolveIntent(Intent intent, String resolvedType,
            int flags, int userId) {
這個方法裡有個呼叫,這個方法意思大概是查詢符合條件所有的activity資訊,存到一個list中,後面都是在查詢返回這個list
final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType,
                    flags, userId);


7、還是這個類PackageManagerService.java


private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
            String resolvedType, int flags, int userId)


在這個方法中有這個方法
List<ResolveInfo> result = mActivities.queryIntent(
                        intent, resolvedType, flags, userId);


8、這是個內部類,mActivities 是這個內部類的一個例項
final class ActivityIntentResolver
            extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo>


方法呼叫如下
public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags,
                int userId) {
            if (!sUserManager.exists(userId)) return null;
            mFlags = flags;
            return super.queryIntent(intent, resolvedType,
                    (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId);
        }
根據剛才的flag (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0 這個值應該是個true == defaultOnly
又呼叫了父類的這個方法
9、IntentResolver.java
父類方法如下
public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly,
            int userId)
其中
buildResolveList(intent, categories, debug, defaultOnly,
                    resolvedType, scheme, firstTypeCut, finalList, userId);


在這個方法裡
 if (!defaultOnly || filter.hasCategory(Intent.CATEGORY_DEFAULT)) {
                    final R oneResult = newResult(filter, match, userId);
                    if (oneResult != null) {
                        dest.add(oneResult);
                        if (debug) {
                            dumpFilter(logPrintWriter, "    ", filter);
                            logPrintWriter.flush();
                            filter.dump(logPrinter, "    ");
                        }
                    }
                } else {
                    hasNonDefaults = true;
                }


只有當filter中有Intent.CATEGORY_DEFAULT或者當defaultOnly == false,才會結果新增到list,因為這裡defaultOnly已經是true了,如果沒有這filiter中新增Intent.CATEGORY_DEFAULT不會新增到list中,因此在Mainfest中必須要新增。
<category android:name="android.intent.category.DEFAULT"/>
為什麼要有這種機制,filter.hasCategory(Intent.CATEGORY_DEFAULT),返回值有很多false,是LAUNCH的啟動的。
3)data
<data android:scheme="string"
                        android:host="string"
                        android:port="string"
                        android:path="string"
                        android:pathPattern="string"
                        android:pathPrefix="string"
                        android:mimeType="sting"
                        />


Uri的格式:scheme://host:port/path or pathPrefix or pathPattern
跟action類似 對應著下面的這個URI。
含義 scheme: 模式 http、file、content
host: 主機名
path:路徑,pathPrefix 正則表示式 ,pathPattern含有萬用字元“*”的路徑
 intent.setDataAndType
對應寫上就可以了.