【Android源码】Intent 源码分析

在Android中,我们经常需要使用到Intent类,它用于跳转Activity、启动Service、发布广播等功能,它是系统各组件之间的纽带,也可以通过Intent传递数据,因为有Intent才使得Android的组件耦合度降低。

原型模式

首先我们跳转到Intent.java:

public class Intent implements Parcelable, Cloneable {
}
复制代码

我们可以发现Intent实现了Cloneable接口,所以我们可以得出一个结论,Intent使用了原型设计模式,(原型设计模式介绍参考:点击此处)我们搜索clone()方法:

@Override
public Object clone() {
   return new Intent(this);
}

public Intent(Intent o) {
   this.mAction = o.mAction;
   this.mData = o.mData;
   this.mType = o.mType;
   this.mPackage = o.mPackage;
   this.mComponent = o.mComponent;
   this.mFlags = o.mFlags;
   this.mContentUserHint = o.mContentUserHint;
   if (o.mCategories != null) {
       this.mCategories = new ArraySet<String>(o.mCategories);
   }
   if (o.mExtras != null) {
       this.mExtras = new Bundle(o.mExtras);
   }
   if (o.mSourceBounds != null) {
       this.mSourceBounds = new Rect(o.mSourceBounds);
   }
   if (o.mSelector != null) {
       this.mSelector = new Intent(o.mSelector);
   }
   if (o.mClipData != null) {
       this.mClipData = new ClipData(o.mClipData);
   }
}
复制代码

Intent如何工作

Intent在使用的时候,可以通过添加flag、category还有需要跳转的对象等来实现功能,那么Intent是如何通过查找并匹配所需要跳转的Activity呢?

  1. app信息表的构建

    参见PackageManagerService 浅析

  2. 匹配

    当app信息表被构建好之后,Intent就可以通过信息表来匹配。

    我们以启动某个具体的Activity来分析,首先我们启动的代码是这样的:

    // 显式Intent
    Intent intent = new Intent(this, SecondActivity.class);
    startActivity(intent);
    
    // 隐式Intent
    Intent intent = new Intent(Intent.ACTION_SENDTO);
    startActivity(intent);
    复制代码

    startActivity方法,通过一系列的调用:

    @Override
    public void startActivity(Intent intent) {
       this.startActivity(intent, null);
    }
    @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
       if (options != null) {
           startActivityForResult(intent, -1, options);
       } else {
           // Note we want to go through this call for compatibility with
           // applications that may have overridden the method.
           startActivityForResult(intent, -1);
       }
    }
    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
           @Nullable Bundle options) {
       if (mParent == null) {
       		// 启动Activity
           Instrumentation.ActivityResult ar =
               mInstrumentation.execStartActivity(
                   this, mMainThread.getApplicationThread(), mToken, this,
                   intent, requestCode, options);
          // 发送启动请求
           if (ar != null) {
               mMainThread.sendActivityResult(
                   mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                   ar.getResultData());
           }
           cancelInputsAndStartExitTransition(options);
       } else {
       }
    }
    复制代码

    最终调用的是startActivityForResult方法,在这个方法中直接调用execStartActivity方法启动Activity:

    public ActivityResult execStartActivity(
           Context who, IBinder contextThread, IBinder token, Activity target,
           Intent intent, int requestCode, Bundle options) {
       IApplicationThread whoThread = (IApplicationThread) contextThread;
       Uri referrer = target != null ? target.onProvideReferrer() : null;
       try {
       		// 将Intent数据添加到剪切板上
           intent.migrateExtraStreamToClipData();
           	// 准备离开当前进程
           intent.prepareToLeaveProcess(who);
           	// 调用ActivityManagerService的startActivity方法
           int result = ActivityManagerNative.getDefault()
               .startActivity(whoThread, who.getBasePackageName(), intent,
                       intent.resolveTypeIfNeeded(who.getContentResolver()),
                       token, target != null ? target.mEmbeddedID : null,
                       requestCode, 0, null, options);
      		// 检查并回调给调用者
           checkStartActivityResult(result, intent);
       } catch (RemoteException e) {
           throw new RuntimeException("Failure from system", e);
       }
       return null;
    }
    复制代码

    execStartActivity方法里面其实就是调用了ActivityManagerService的startActivity方法:

    final int startActivity(Intent intent, ActivityStackSupervisor.ActivityContainer container) {
        enforceNotIsolatedCaller("ActivityContainer.startActivity");
        final int userId = mUserController.handleIncomingUser(Binder.getCallingPid(),
                Binder.getCallingUid(), mStackSupervisor.mCurrentUser, false,
                ActivityManagerService.ALLOW_FULL_ONLY, "ActivityContainer", null);
    
        // TODO: Switch to user app stacks here.
        String mimeType = intent.getType();
        final Uri data = intent.getData();
        if (mimeType == null && data != null && "content".equals(data.getScheme())) {
            mimeType = getProviderMimeType(data, userId);
        }
        container.checkEmbeddedAllowedInner(userId, intent, mimeType);
    
        intent.addFlags(FORCE_NEW_TASK_FLAGS);
        return mActivityStarter.startActivityMayWait(null, -1, null, intent, mimeType, null, null, null,
                null, 0, 0, null, null, null, null, false, userId, container, null);
    }
    复制代码

    这个方法会调用ActivityStarter的startActivityMayWait方法,这个方法中又会调用ActivityStackSupervisor.resolveIntent方法,而这个方法就是调用的PMS的resolveIntent方法:

    // 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;
    }	
    
    // PackageManagerService.java
    @Override
    public ResolveInfo resolveIntent(Intent intent, String resolvedType,
           int flags, int userId) {
       try {
           Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveIntent");
    
           if (!sUserManager.exists(userId)) return null;
           flags = updateFlagsForResolve(flags, userId, intent);
           enforceCrossUserPermission(Binder.getCallingUid(), userId,
                   false /*requireFullPermission*/, false /*checkShell*/, "resolve intent");
    
           Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "queryIntentActivities");
           // 获取列表
           final List<ResolveInfo> query = queryIntentActivitiesInternal(intent, resolvedType,
                   flags, userId);
           Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
    			// 通过列表选择出最合适的info对象
           final ResolveInfo bestChoice =
                   chooseBestActivity(intent, resolvedType, flags, query, userId);
    
           if (isEphemeralAllowed(intent, query, userId)) {
               Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
               final EphemeralResolveInfo ai =
                       getEphemeralResolveInfo(intent, resolvedType, userId);
               if (ai != null) {
                   if (DEBUG_EPHEMERAL) {
                       Slog.v(TAG, "Returning an EphemeralResolveInfo");
                   }
                   bestChoice.ephemeralInstaller = mEphemeralInstallerInfo;
                   bestChoice.ephemeralResolveInfo = ai;
               }
               Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
           }
           return bestChoice;
       } finally {
           Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
       }
    }	
    复制代码

    queryIntentActivitiesInternal方法返回的结果就是符合intent的ActivityInfo列表:

    private @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,
           String resolvedType, int flags, int userId) {
       // 获取Intent的Component对象
       ComponentName comp = intent.getComponent();
       if (comp == null) {
           if (intent.getSelector() != null) {
               intent = intent.getSelector();
               comp = intent.getComponent();
           }
       }
    	// 不为空,是显式Intent,直接获取到ActivityInfo返回
       if (comp != null) {
           final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
           final ActivityInfo ai = getActivityInfo(comp, flags, userId);
           if (ai != null) {
               final ResolveInfo ri = new ResolveInfo();
               ri.activityInfo = ai;
               list.add(ri);
           }
           return list;
       }
    	
       // 为空,是隐式Intent
       synchronized (mPackages) {
           final String pkgName = intent.getPackage();
           if (pkgName == null) {
               // 代码省略
               return result;
           }
           // 通过包名获取到Package对象
           final PackageParser.Package pkg = mPackages.get(pkgName);
           if (pkg != null) {
           		// 在获取到ActivityInfo对象
               return filterIfNotSystemUser(
                       mActivities.queryIntentForPackage(
                               intent, resolvedType, flags, pkg.activities, userId),
                       userId);
           }
           return new ArrayList<ResolveInfo>();
       }
    }	
    复制代码

    上面这个方法就是Intent获取到ActivityInfo的核心,它的大致过程如下:

    1. 首先获取Intent的Component对象,如果不为空,说明指定了Componet,那么就直接通过Componet找到ActivityInfo列表,并且这个列表size为1,所以这个ActivityInfo就是指定需要跳转的组件。
    2. 如果没有指定Component,那就是隐式Intent调用,接着获取Intent传递的需要跳转的包名。
    3. 如果包名为空,则会通过ActivityIntentResolver等进行模糊匹配,比如根据Action、Category等。
    4. 如果包名不为空,则直接根据包名来获取到对应的ActivityInfo对象,而mActivities就是PMS存储的activity信息表。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值