Android startActivity源码分析

静下心来打算看看android源码,就从startActivity这个最常见的函数开始一步步分析下去。

    @Override
    public void startActivity(Intent intent) {
        this.startActivity(intent, null);
    }

首先看到startActivity 调用一个重载的方法,第二个Bundle 传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);
        }
    }

可以看到Bundle options 这个入参为null 会走到 startActivityForResult(intent, -1);
我们继续看

 public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
        startActivityForResult(intent, requestCode, null);
    }

如上面那注释说的一样,只是通过这个调用来兼容。这里我们可以看出归根结底都是调用startActivityForResult。

接下来看看startActivityForResult方法,考虑到篇幅,注释已经去掉了。。

     public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        if (mParent == null) {
            options = transferSpringboardActivityOptions(options);
            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());
            }
            if (requestCode >= 0) {

                mStartedActivity = true;
            }

            cancelInputsAndStartExitTransition(options);
        } else {
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
         
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
    }

看到第一行if(mParent == null)这个mParent是什么鬼。定位一下!!!

  /*package*/ ActivityInfo mActivityInfo;
    /*package*/ ActivityThread mMainThread;
    Activity mParent;
    boolean mCalled;
    /*package*/ boolean mResumed;
    /*package*/ boolean mStopped;

在成员变量里看到了它,大家都知道ActivityGroup这玩意,所以看这个activity之间也有了父子关系。我们今天先看一般情况走进if(mParent == null)。又看到一个幺蛾子
transferSpringboardActivityOptions(options); 字面翻译 传送跳板活动选项。。。来挖掘下它的作用

 private Bundle transferSpringboardActivityOptions(Bundle options) {
        if (options == null && (mWindow != null && !mWindow.isActive())) {
            final ActivityOptions activityOptions = getActivityOptions();
            if (activityOptions != null &&
                    activityOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) {
                return activityOptions.toBundle();
            }
        }
        return options;
    }

当options为空,窗体不为空,且不在活动中。。。看到一个东西ActivityOptions ,百度一下原来是转场动画。
有兴趣可以看下Android 使用ActivityOptions实现Activity转场动画
花里胡哨的我们先不深究,回到主逻辑上下面一大段

 Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
    

新朋友 Instrumentation 英文解释 n. 使用仪器,装设仪器; 乐器法; 乐曲研究; 手段;
在继续深入探索之前,我们先把其他边边角角的内容稍微解释下

  if (ar != null) {
                mMainThread.sendActivityResult(
                    mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                    ar.getResultData());
            }
            if (requestCode >= 0) {
                mStartedActivity = true;
            }

            cancelInputsAndStartExitTransition(options);



   private void cancelInputsAndStartExitTransition(Bundle options) {
        final View decor = mWindow != null ? mWindow.peekDecorView() : null;
        if (decor != null) {
            decor.cancelPendingInputEvents();
        }
        if (options != null && !isTopOfTask()) {
            mActivityTransitionState.startExitOutTransition(this, options);
        }
    }

除了后面的动画取消输入事件,对之前ar!=null 之后sendActivityResult 有段注释可以看看

 // If this start is requesting a result, we can avoid making
                // the activity visible until the result is received.  Setting
                // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                // activity hidden during this time, to avoid flickering.
                // This can only be done when a result is requested because
                // that guarantees we will get information back when the
                // activity is finished, no matter what happens to it.

大概就是调用start是为了图个结果。。。
用android studio 看源码会发现看到mInstrumentation.execStartActivity 冒红,点不进去。
这是谷歌不让你看, 需要借助外力 Android Studio 查看Android内部隐藏源码

继续

    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;
        if (referrer != null) {
            intent.putExtra(Intent.EXTRA_REFERRER, referrer);
        }
        if (mActivityMonitors != null) {
            synchronized (mSync) {
                final int N = mActivityMonitors.size();
                for (int i=0; i<N; i++) {
                    final ActivityMonitor am = mActivityMonitors.get(i);
                    ActivityResult result = null;
                    if (am.ignoreMatchingSpecificIntents()) {
                        result = am.onStartActivity(intent);
                    }
                    if (result != null) {
                        am.mHits++;
                        return result;
                    } else if (am.match(who, null, intent)) {
                        am.mHits++;
                        if (am.isBlocking()) {
                            return requestCode >= 0 ? am.getResult() : null;
                        }
                        break;
                    }
                }
            }
        }
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);
            int result = ActivityManager.getService()
                .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;
    }

这个方法有7个入参,真的挺多的。
who:this
target: this
两个IBinder
token: 标示自己
contextThread: 看到下一行强转成IApplicationThread 多么熟悉,你看它源码就知道了binder通信。跟你自己写aidl ,系统帮你生成的一样,跨进程通信,又类似于远程方法调用,IApplicationThread是一个接口

public interface IApplicationThread extends IInterface {
    void schedulePauseActivity(IBinder var1, boolean var2, boolean var3, int var4, boolean var5) throws RemoteException;

    void scheduleStopActivity(IBinder var1, boolean var2, int var3) throws RemoteException;

    void scheduleWindowVisibility(IBinder var1, boolean var2) throws RemoteException;

    void scheduleResumeActivity(IBinder var1, int var2, boolean var3, Bundle var4) throws RemoteException;

    void scheduleSendResult(IBinder var1, List<ResultInfo> var2) throws RemoteException;

    void scheduleLaunchActivity(Intent var1, IBinder var2, int var3, ActivityInfo var4, Configuration var5, Configuration var6, CompatibilityInfo var7, String var8, IVoiceInteractor var9, int var10, Bundle var11, PersistableBundle var12, List<ResultInfo> var13, List<ReferrerIntent> var14, boolean var15, boolean var16, ProfilerInfo var17) throws RemoteException;

    void scheduleNewIntent(List<ReferrerIntent> var1, IBinder var2, boolean var3) throws RemoteException;

    void scheduleDestroyActivity(IBinder var1, boolean var2, int var3) throws RemoteException;

    void scheduleReceiver(Intent var1, ActivityInfo var2, CompatibilityInfo var3, int var4, String var5, Bundle var6, boolean var7, int var8, int var9) throws RemoteException;

    void scheduleCreateService(IBinder var1, ServiceInfo var2, CompatibilityInfo var3, int var4) throws RemoteException;

    void scheduleStopService(IBinder var1) throws RemoteException;

    void bindApplication(String var1, ApplicationInfo var2, List<ProviderInfo> var3, ComponentName var4, ProfilerInfo var5, Bundle var6, IInstrumentationWatcher var7, IUiAutomationConnection var8, int var9, boolean var10, boolean var11, boolean var12, boolean var13, Configuration var14, CompatibilityInfo var15, Map var16, Bundle var17, String var18) throws RemoteException;

    void scheduleExit() throws RemoteException;

    void scheduleConfigurationChanged(Configuration var1) throws RemoteException;

    void scheduleServiceArgs(IBinder var1, ParceledListSlice var2) throws RemoteException;

    void updateTimeZone() throws RemoteException;

    void processInBackground() throws RemoteException;

    void scheduleBindService(IBinder var1, Intent var2, boolean var3, int var4) throws RemoteException;

    void scheduleUnbindService(IBinder var1, Intent var2) throws RemoteException;

    void dumpService(ParcelFileDescriptor var1, IBinder var2, String[] var3) throws RemoteException;

    void scheduleRegisteredReceiver(IIntentReceiver var1, Intent var2, int var3, String var4, Bundle var5, boolean var6, boolean var7, int var8, int var9) throws RemoteException;

    void scheduleLowMemory() throws RemoteException;

    void scheduleActivityConfigurationChanged(IBinder var1, Configuration var2) throws RemoteException;

去掉方法的前缀名schedule,大家是不是都有似曾相识的感觉。

   public abstract static class Stub extends Binder implements IApplicationThread {
        private static final String DESCRIPTOR = "android.app.IApplicationThread";
        static final int TRANSACTION_schedulePauseActivity = 1;
        static final int TRANSACTION_scheduleStopActivity = 2;
        static final int TRANSACTION_scheduleWindowVisibility = 3;
        static final int TRANSACTION_scheduleResumeActivity = 4;
        static final int TRANSACTION_scheduleSendResult = 5;
        static final int TRANSACTION_scheduleLaunchActivity = 6;
        static final int TRANSACTION_scheduleNewIntent = 7;
        static final int TRANSACTION_scheduleDestroyActivity = 8;
	   ......

        public Stub() {
            this.attachInterface(this, "android.app.IApplicationThread");
        }

        public static IApplicationThread asInterface(IBinder obj) {
            if (obj == null) {
                return null;
            } else {
                IInterface iin = obj.queryLocalInterface("android.app.IApplicationThread");
                return (IApplicationThread)(iin != null && iin instanceof IApplicationThread ? (IApplicationThread)iin : new IApplicationThread.Stub.Proxy(obj));
            }
        }

        public IBinder asBinder() {
            return this;
        }

        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        ...

多么的熟悉啊,好啦,就不扯它 了。

Uri referrer = target != null ? target.onProvideReferrer() : null;
        if (referrer != null) {
            intent.putExtra(Intent.EXTRA_REFERRER, referrer);
        }

target.onProvideReferrer方法没覆写,是个null.

 if (mActivityMonitors != null) {
            synchronized (mSync) {
                final int N = mActivityMonitors.size();
                for (int i=0; i<N; i++) {
                    final ActivityMonitor am = mActivityMonitors.get(i);
                    ActivityResult result = null;
                    if (am.ignoreMatchingSpecificIntents()) {
                        result = am.onStartActivity(intent);
                    }
                    if (result != null) {
                        am.mHits++;
                        return result;
                    } else if (am.match(who, null, intent)) {
                        am.mHits++;
                        if (am.isBlocking()) {
                            return requestCode >= 0 ? am.getResult() : null;
                        }
                        break;
                    }
                }
            }
        }

这个就先不用管了,又是谷歌测试的那一套东西。继续

 try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);
            int result = ActivityManager.getService()
                .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;

第一行 粗略的判断是给一些action 加权限,我们不管。
第二行我们不打算去其他进程不考虑。

重头戏来了ActivityManager.getService().startActivity 。。。AM出现,

 /**
     * @hide
     */
    public static IActivityManager getService() {
        return IActivityManagerSingleton.get();
    }

    private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };
public abstract class Singleton<T> {
    private T mInstance;

    protected abstract T create();

    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}

懒加载的单例模式+范型,单例复习下,很多种,double check, 枚举,饿汉,静态内部类,容器实现,面试必考!!!

    /** @hide */
    public static void checkStartActivityResult(int res, Object intent) {
        if (!ActivityManager.isStartResultFatalError(res)) {
            return;
        }

        switch (res) {
            case ActivityManager.START_INTENT_NOT_RESOLVED:
            case ActivityManager.START_CLASS_NOT_FOUND:
                if (intent instanceof Intent && ((Intent)intent).getComponent() != null)
                    throw new ActivityNotFoundException(
                            "Unable to find explicit activity class "
                            + ((Intent)intent).getComponent().toShortString()
                            + "; have you declared this activity in your AndroidManifest.xml?");
                throw new ActivityNotFoundException(
                        "No Activity found to handle " + intent);
            case ActivityManager.START_PERMISSION_DENIED:
                throw new SecurityException("Not allowed to start activity "
                        + intent);
            case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
                throw new AndroidRuntimeException(
                        "FORWARD_RESULT_FLAG used while also requesting a result");
            case ActivityManager.START_NOT_ACTIVITY:
                throw new IllegalArgumentException(
                        "PendingIntent is not an activity");
            case ActivityManager.START_NOT_VOICE_COMPATIBLE:
                throw new SecurityException(
                        "Starting under voice control not allowed for: " + intent);
            case ActivityManager.START_VOICE_NOT_ACTIVE_SESSION:
                throw new IllegalStateException(
                        "Session calling startVoiceActivity does not match active session");
            case ActivityManager.START_VOICE_HIDDEN_SESSION:
                throw new IllegalStateException(
                        "Cannot start voice activity on a hidden session");
            case ActivityManager.START_ASSISTANT_NOT_ACTIVE_SESSION:
                throw new IllegalStateException(
                        "Session calling startAssistantActivity does not match active session");
            case ActivityManager.START_ASSISTANT_HIDDEN_SESSION:
                throw new IllegalStateException(
                        "Cannot start assistant activity on a hidden session");
            case ActivityManager.START_CANCELED:
                throw new AndroidRuntimeException("Activity could not be started for "
                        + intent);
            default:
                throw new AndroidRuntimeException("Unknown error code "
                        + res + " when starting " + intent);
        }
    }

拿着上一个的远程调用结果,判断是否要抛出异常。又是一大堆老朋友“ have you declared this activity in your AndroidManifest.xml?”

猜你喜欢

转载自blog.csdn.net/atxxiang4/article/details/82851899