Android中高级进阶

关于Activity你必须掌握的知识(本篇基于8.0去分析)

2019-03-20  本文已影响32人  Sincerity_

@[TOC]

1. Activity启动模式以及使用场景?

  1. standard 标准模式 使用场景: 邮件,默认使用标准模式
  2. singleTop 栈顶复用 :登录页面 ,微信支付 微信回调,推送通知栏等
  3. singleTask 栈内单例模式: 主页面等重复调用的页面
  4. singleInstance 栈内单例模式 系统Launcher, 锁屏页面等,此种模式下系统会为这个模式下的Activity单独开辟一个栈
  5. 总结 singleTop ,singleTask ,singleInstance 三种模式如果应用内存在Activity的实例,就不会重新去创建Activity的实例,而是调用Activity的onNewIntent函数 从而Activity的oncreate和onstart没有被调用
  6. 关于singleInstance 必须知道的故事一: 此时有三个activity,ActivityA,ActivityB,ActivityC,除了ActivityB的启动模式为singleInstance,其他的启动模式都为默认的。在ActivityA里startActivity了一个ActivityB,在ActivityB里startActivity了一个ActivityC。照理来说在当前ActivityC页面按返回键,finish当前界面后应当回到ActivityB界面,但是页面直接回到了ActivityA
  1. 故事二:有两个ActivityA,ActivityB,ActivityA的启动模式为默认的,ActivityB的启动模式为singleInstance。当在ActivityA里startActivity了ActivityB,当前页面为ActivityB。按下home键。应用退到后台。此时再点击图标进入APP,按照天理来说,此时的界面应该是ActivityB,可是奇迹又出现了,当前显示的界面是ActivityA
  1. 说了这么多 如果想让Activity回到我们想让它返回的地方如何做呢?

2. taskAffinity属性

taskAffinity属性和Activity的启动模式息息相关, 这个属性在mainfest中设置,可以理解为taskAffinity为宿主Activity指定了存放的任务栈, taskAffinity只有和singleTask启动模式匹配使用,启动的Activity才会运行在名字和taskAffinity相同的任务栈中

3. onSaveInstanceState()和onRestoreInstanceState()

4. onConfigurationChanged()属性屏幕旋转

5. (主要)Activity 到底是如何启动的

  1. 涉及的名词简介,
  2. Launcher请求AMS过程
    3.AMS到ActivityThread的调用过程,
    4.ActivityThread启动Activity的过程

1. 涉及的类名介绍:

2. Launcher请求AMS的过程

3. AMS到ActivityThread的调用过程

AMS收到startActivity的请求之后,会按照如下的方法链进行调用

 //AMS中Activity的启动入口
    @Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
                                   Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
      
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
                resultWho, requestCode, startFlags, profilerInfo, bOptions,
                UserHandle.getCallingUserId());
    }

在这里又出现了一个新对象ActivityStackSupervisor,通过这个类可以实现对ActivityStack的部分操作

 @Override
 public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
                                         Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
                                         int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
        //判断调进程用者是否被隔离 如果隔离会有SecurityException异常
        enforceNotIsolatedCaller("startActivity");
        //检查调用者权限 没有权限也会有SecurityException异常
        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                userId, false, ALLOW_FULL_ONLY, "startActivity", null);

        // TODO: Switch to user app stacks here.
        return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, bOptions, false, userId, null, null,
                "startActivityAsUser");
    }

ActivityStarter类中的操作

    final int startActivityMayWait(IApplicationThread caller, int callingUid,...){
      ...
                //这个ActivityStarter主要作用,加载Activity控制类,收集所有的逻辑来决定intent和flags转为               //Activity并且将Activity和Task以及Stack相关联
            final ActivityRecord[] outRecord = new ActivityRecord[1];
            int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
                    aInfo, rInfo, voiceSession, voiceInteractor,
                    resultTo, resultWho, requestCode, callingPid,
                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                    options, ignoreTargetSecurity, componentSpecified, outRecord, container,
                    inTask, reason);
      ...
    }

int startActivityLocked(...) {

        if (TextUtils.isEmpty(reason)) { //启动理由reason
            throw new IllegalArgumentException("Need to specify a reason.");
        }
       ...
            //startActivity()
        mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
                aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
                callingPid, callingUid, callingPackage, realCallingPid, realCallingUid,                                startFlags,options, ignoreTargetSecurity, componentSpecified,                                             mLastStartActivityRecord,container, inTask);
        ...
        return mLastStartActivityResult;
    }
 private int startActivity(...){
   ...
    // 即将要启动的Activity的描述类ActivityRecord (用来记录Activty的所有信息)
       ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
                callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
                resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
                mSupervisor, container, options, sourceRecord);
     ...
        return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
                options, inTask, outActivity);
 }
 private int startActivity(...) {
        int result = START_CANCELED;
        try {
            mService.mWindowManager.deferSurfaceLayout();
            result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, outActivity);
        }
   ...
        return result;
    }
private int startActivityUnchecked(...) {
...
                mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                        mOptions);
  ...
}

ActivityStackSupervisor # resumeFocusedStackTopActivityLocked

    boolean resumeFocusedStackTopActivityLocked(ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
        if (targetStack != null && isFocusedStack(targetStack)) {
            return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
        }
        //获取要启动的Activity 并且所在栈的栈顶的不是处于停止状态的ActivityRecord
        final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
        if (r == null || r.state != RESUMED) {
            //继续执行ActivityStack # resumeTopActivityUncheckedLocked
            mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
        } else if (r.state == RESUMED) {
            // Kick off any lingering app transitions form the MoveTaskToFront operation.
            mFocusedStack.executeAppTransition(targetOptions);
        }
        return false;
    }

ActivityStack # resumeTopActivityUncheckedLocked

boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
        if (mStackSupervisor.inResumeTopActivity) {
            // Don't even start recursing.
            return false;
        }
        boolean result = false;
        try {
            // Protect against recursion.
            mStackSupervisor.inResumeTopActivity = true;
            //继续执行
            result = resumeTopActivityInnerLocked(prev, options);
        } finally {
            mStackSupervisor.inResumeTopActivity = false;
        }
        mStackSupervisor.checkReadyForSleepLocked();

        return result;
    }
 private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
        if (!mService.mBooting && !mService.mBooted) {
            // Not ready yet!
            return false;
        }
   ...
      mStackSupervisor.startSpecificActivityLocked(next, true, true);
     ...
 }

ActivityStackSupervisor # startSpecificActivityLocked

void startSpecificActivityLocked(ActivityRecord r,
                                     boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        //获取即将要启动的Activity的所在的应用程序进程
      ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);

        r.getStack().setLaunchTime(r);
        //判断要启动的 Activity 所在的应用程序进程如果已经运行
        if (app != null && app.thread != null) {
            try {
                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                        || !"android".equals(r.info.packageName)) {
                    // Don't add this if it is a platform component that is marked
                    // to run in multiple processes, because this is actually
                    // part of the framework so doesn't make sense to track as a
                    // separate apk in the process.
                    app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                            mService.mProcessStats);
                }
                //继续执行
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
            }
        }

        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }
final boolean realStartActivityLocked(...){
  ...
     //app.thread 指的IApplicationThread它的实现是 ActivityThread 的内部类 ApplicationThread
     // 段代码指的就是要在目标应用程序进程启动 Activity
     //app指的是传入的要启动的Activity所在的应用程序进程 代码只要目的就是要在目标引用程序启动Activity
     //当前代码运行在AMS所在的基础进程(SystemServer进程)中,通过ApplicationThread来与应用程序进行BInder         通信,所以ApplicationThread就是AMS和应用程序通信的桥梁
     app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info,
                    mergedConfiguration.getGlobalConfiguration(),
                    mergedConfiguration.getOverrideConfiguration(), r.compat,
                    r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                    r.persistentState, results, newIntents, !andResume,
                    mService.isNextTransitionForward(), profilerInfo);
    ...
}

看一下时序图再说 源码来回切换有点乱

AMS调用ActivityThread过程.png

4. ActivityThread启动Activity的过程

​ ActivityThread通过BInder接收到AMS发送过来的启动Activity的启动通知调用ApplicationThread的scheduleLaunchActivity方法 因为AMS启动Activity的时候用的 app.thread.scheduleLaunchActivityapp.thread是调用ProcessRecord.IApplicationThread对象,ApplicationThread继承于IApplicationThread.stub 所以执行ActivityThread#ApplicationThread#scheduleLaunchActivity方法

  private class ApplicationThread extends IApplicationThread.Stub {
    ...
        @Override
      public final void scheduleLaunchActivity(){
      ...
        //得到Binder传递过来的消息封装到ActivityClientRecord对象中发送给H H是一个消息进程管理类
       sendMessage(H.LAUNCH_ACTIVITY, r);
    }
      ...
  }

ActivityThread#H #handleMessage

 public void handleMessage(Message msg) {
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    //将ApplicationThread传递过来的参数转换成ActivityClientRecode对象
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
                    //应用程序进程需要启动Activity时需要将改Activity所属的APK加载进来
                    //而 r.packageInfo返回一个loadedAPk,loadedAPk就是用来描述已加载APK文件的
                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    //继续执行
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                }
            }
 }
    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {         ....
      //初始化WindowManager
        WindowManagerGlobal.initialize();
        //启动Activity
        Activity a = performLaunchActivity(r, customIntent);

        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            reportSizeConfigurations(r);
            Bundle oldState = r.state;
            //将Activity的状态设置为Resume
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);

            if (!r.activity.mFinished && r.startsNotResumed) {
                //去执行将Activity状态设置为Resume
                performPauseActivityIfNeeded(r, reason);
                if (r.isPreHoneycomb()) {
                    r.state = oldState;
                }
            }
        } else {
           //如果出现错误通知AMS关闭当前Activity
            try {
                ActivityManager.getService()
                        .finishActivity(r.token, Activity.RESULT_CANCELED, null,
                                Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
        }
    }
 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
   ...
       appContext.setOuterContext(activity);
                //初始化Activity activity.attach方法中会创建Window对象并且与Activity自身关联
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);
     ...
         //Instrumentation.callActivityOnCreate来启动Activity 继续执行
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
   ....
 }

Instrumentation#callActivityOnCreate

 public void callActivityOnCreate(Activity activity, Bundle icicle,
            PersistableBundle persistentState) {
        prePerformCreate(activity);
        activity.performCreate(icicle, persistentState);
        postPerformCreate(activity);
    }

Activity#performCreate

  final void performCreate(Bundle icicle) {
    //释放启动Activity过程中需要的权限
        restoreHasCurrentPermissionRequest(icicle);
        //调用Activity的onCreate方法 ,根Activity就启动完毕 
        onCreate(icicle);
        mActivityTransitionState.readState(icicle);
        performCreateCommon();
    }

终于一个完成的Activity到此就启动完成了...看一下时序图吧 -眼睛都疼....

ActivityThread启动Activity的过程.png

上面这些调用过程非常复杂,源码中各种条件判断让人眼花缭乱,所以说如果你没记住也没关系,你只要记住这个流程,理解了Android在控制Activity生命周期时是如何操作,以及是通过哪几个关键的类进行操作的就可以了,

总结一下 Activity的启动流程:

​ 用户在Launcher程序里点击应用图标时,会通知AMS启动应用的入口Activity,AMS发现这个应用还未启动,则会通知Zygote进程孵化出应用进程,然后在这个dalvik应用进程里执行ActivityThread的main方法。应用进程接下来通知AMS应用进程已启动,AMS保存应用进程的一个代理对象,这样AMS可以通过这个代理对象控制应用进程,然后AMS通知应用进程创建入口Activity的实例,并执行它的生命周期方法

现在也可以理解:

​ 如果应用的组件(包括所有组件Activity,Service,ContentProvider,Receiver) 被启动,肯定会先启动以应用包名为进程名的进程,这些组件都会运行在应用包名为进程名的进程里,并且是在主线程里。应用进程启动时会先创建Application对象,并执行Application对象的生命周期方法,然后才启动应用的组件。

​ 有一种情况比较特殊,那就是为组件设置了特殊的进程名,也就是说通过android:process设置进程名的情况,此时组件运行在单独的进程内。

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);
        }
    }
//但是RESULT_OK  = -1;
public static final int RESULT_OK  = -1;
//得出结论 如果用RESULT_OK  作为请求码 你不可能从onActivityResult()里面收到任何回调.
startActivityForResult(intent,RESULT_OK) = startActivity()

本文链接地址

上一篇下一篇

猜你喜欢

热点阅读