第二次启动android app的过程分析

来源:互联网 发布:分析成绩的软件 编辑:程序博客网 时间:2024/05/22 17:36

网上关于在Launcher上第一次启动app的过程分析已经很多了,今天吃饭的时候在思考一个问题:我在Launcher上打开淘宝,切换到购物车,按Home键回到Launcher,再次点开淘宝的时候仍然是购物车页面。按说Launcher每次点开app都是启动同一个activityACTION_MAIN , CATEGORY_LAUNCHER),那么这步转换是在哪里完成的呢?

回来翻了翻代码,找到了答案:(有点长,后面会一步一步分析)

final int startActivityUncheckedLocked(final ActivityRecord r, ActivityRecord sourceRecord,      IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,        boolean doResume, Bundle options, TaskRecord inTask) {    ... ...    boolean addingToTask = false;    TaskRecord reuseTask = null;    ... ...    if (((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&            (launchFlags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)        if (inTask == null && r.resultTo == null) {            ActivityRecord intentActivity = !launchSingleInstance ?                    findTaskLocked(r) : findActivityLocked(intent, r.info);            if (intentActivity != null) {                ... ...                if (r.task == null) {                    r.task = intentActivity.task;                }                if (intentActivity.task.intent == null) {                    intentActivity.task.setIntent(r);                }                targetStack = intentActivity.task.stack;                targetStack.mLastPausedActivity = null;                final ActivityStack focusStack = getFocusedStack();                ActivityRecord curTop = (focusStack == null)                        ? null : focusStack.topRunningNonDelayedActivityLocked(notTop);                boolean movedToFront = false;                if (curTop != null && (curTop.task != intentActivity.task ||                    curTop.task != focusStack.topTask())) {                    r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);                    if (sourceRecord == null || (sourceStack.topActivity() != null &&                        sourceStack.topActivity().task == sourceRecord.task)) {                        ... ...                        movedHome = true;                        targetStack.moveTaskToFrontLocked(intentActivity.task,                                       noAnimation, options, r.appTimeTracker,                                        "bringingFoundTaskToFront");                        movedToFront = true;                        ... ...                    }                ... ...                }                ... ...                if (!addingToTask && reuseTask == null) {                    // We didn't do anything...  but it was needed (a.k.a., client                    // don't use that intent!)  And for paranoia, make                    // sure we have correctly resumed the top activity.                    if (doResume) {                        targetStack.resumeTopActivityLocked(null, options);                        if (!movedToFront) {                            // Make sure to notify Keyguard as well if we are not running                             // an app transition later.                            notifyActivityDrawnForKeyguard();                        }                    } else {                        ActivityOptions.abort(options);                    }                    return ActivityManager.START_TASK_TO_FRONT;                }            }        }        ... ...}}

首先从Launcher启动的activity都会带NEW_TASKflag,因此进到这个条件中。

传进来的inTaskr.resultTo都是null,因此调用findTaskLocked()task history里查找是否存在这个activity或者它的affinity(姻亲),如果存在的话就返回当前栈顶的activity。由于是第二次启动app,因此肯定是能查得到的,这样说比较抽象,举个栗子吧:

01-18 23:13:55.870   736  1233 I ActivityManager: START u0 {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.taobao.taobao/com.taobao.tao.welcome.Welcome bnds=[276,276][540,573] (has extras)} from uid 10008 on display 001-18 23:19:23.345   736   906 D ActivityManager: Comparing existing cls=com.taobao.taobao/com.taobao.tao.welcome.Welcome/aff=com.taobao.taobao to new cls=com.taobao.taobao/com.taobao.tao.welcome.Welcome/aff=com.taobao.taobao01-18 23:19:23.345   736   906 D ActivityManager: Found matching affinity!

从这个log可以看出,点击淘宝图标后启动的是com.taobao.tao.welcome.Welcome这个activity,提示找到了它的affinity!看一下findTaskLocked()的代码:

ActivityRecord findTaskLocked(ActivityRecord target) {... ...for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {    final TaskRecord task = mTaskHistory.get(taskNdx);     ... ...    if (!isDocument && !taskIsDocument && task.rootAffinity != null) {        if (task.rootAffinity.equals(target.taskAffinity)) {            if (DEBUG_TASKS) Slog.d(TAG, "Found matching affinity!");                return r;            }        } else if (taskIntent != null && taskIntent.getComponent() != null &&            taskIntent.getComponent().compareTo(cls) == 0 &&            Objects.equals(documentData, taskDocumentData)) {            if (DEBUG_TASKS) Slog.d(TAG, "Found matching class!");            return r;        } else if (affinityIntent != null && affinityIntent.getComponent() != null &&            affinityIntent.getComponent().compareTo(cls) == 0 &&            Objects.equals(documentData, taskDocumentData)) {            if (DEBUG_TASKS) Slog.d(TAG, "Found matching class!");            return r;        } else if (DEBUG_TASKS) {            Slog.d(TAG, "Not a match: " + task);        }    }}return null;}

显然,这里命中了第一个条件判断,存在它的affinity。如果某些情况下不满足这个条件,那就会直接判断component是否相同,也就是是否存在这个activity

如果没有打开AMSlog,从dumpsys上也可以看出来:

ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)Display #0 (activities from top to bottom):  Stack #1:    Task id #45    * TaskRecord{c15fe7c #45 A=com.taobao.taobao U=0 sz=1}      userId=0 effectiveUid=u0a53 mCallingUid=u0a53 mCallingPackage=com.taobao.taobao      affinity=com.taobao.taobao      intent={act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.taobao.taobao/com.taobao.tao.welcome.Welcome}      realActivity=com.taobao.taobao/com.taobao.tao.welcome.Welcome      autoRemoveRecents=false isPersistable=true numFullscreen=1 taskType=0 mTaskToReturnTo=1      rootWasReset=true mNeverRelinquishIdentity=true mReuseTask=false mLockTaskAuth=LOCK_TASK_AUTH_PINNABLE      Activities=[ActivityRecord{f507b27 u0 com.taobao.taobao/com.taobao.tao.homepage.MainActivity3 t45}]      askedCompatMode=false inRecents=true isAvailable=true      lastThumbnail=android.graphics.Bitmap@aa8b708 lastThumbnailFile=/data/system/recent_images/45_task_thumbnail.png      stackId=1      hasBeenVisible=true mResizeable=false firstActiveTime=1453130178152 lastActiveTime=1453130178152 (inactive for 14s)      * Hist #0: ActivityRecord{f507b27 u0 com.taobao.taobao/com.taobao.tao.homepage.MainActivity3 t45}          packageName=com.taobao.taobao processName=com.taobao.taobao          launchedFromUid=10053 launchedFromPackage=com.taobao.taobao userId=0          app=ProcessRecord{6e6642e 18539:com.taobao.taobao/u0a53}          Intent { act=android.intent.action.VIEW dat=http://m.taobao.com/index.htm flg=0x14000000 pkg=com.taobao.taobao cmp=com.taobao.taobao/com.taobao.tao.homepage.MainActivity3 bnds=[318,302][498,482] (has extras) }          frontOfTask=true task=TaskRecord{c15fe7c #45 A=com.taobao.taobao U=0 sz=1}          taskAffinity=com.taobao.taobao          realActivity=com.taobao.taobao/com.taobao.tao.homepage.MainActivity3          baseDir=/data/app/com.taobao.taobao-1/base.apk          dataDir=/data/user/0/com.taobao.taobao          stateNotNeeded=false componentSpecified=true mActivityType=0          compat={480dpi} labelRes=0x7f070259 icon=0x7f020133 theme=0x7f0b0017          config={1.0 ?mcc?mnc en_US ldltr sw360dp w360dp h568dp 480dpi nrml port finger -keyb/v/h -nav/h s.6}          stackConfigOverride={1.0 ?mcc?mnc ?locale ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/?}          taskDescription: iconFilename=null label="null" color=ffe6e6e6          launchFailed=false launchCount=0 lastLaunchTime=-19s881ms          haveState=false icicle=null          state=RESUMED stopped=false delayedResume=false finishing=false          keysPaused=false inHistory=true visible=true sleeping=false idle=true          fullscreen=true noDisplay=false immersive=false launchMode=2          frozenBeforeDestroy=false forceNewConfig=false          mActivityType=APPLICATION_ACTIVITY_TYPE          waitingVisible=false nowVisible=true lastVisibleTime=-14s134ms

看到没?Task history里有一个MainActivity3,也就是淘宝的主界面,它的taskAffinity和要启动的Welcome activity是一样的,都是com.taobao.taobao

在回到文章开头的代码继续分析,得到这个“intentActivity”之后,获取它的targetStack,也就是上面log里的stack 1

下面是获取curTop,也就是当前前台的activity。现在这里curTop就是LaunchercurTop.task肯定不等于intentActivity.task,进入这个条件里。

传进来的sourceRecordnull,因此进入到这个条件里调用targetStackmoveTaskToFrontLocked()方法。这样之前的task就移到stack 1的栈顶了。

再往下就是一马平川了,一路往下看一直到targetStack.resumeTopActivityLocked()。所以我们看到的现象就是:Launcher请求启动一个叫Welcomeactivity,最终执行的操作是resume stack 1栈顶的MainActivity3

多问一个问题:一般我们写app的时候很少用到taskAffinity属性,默认的taskAffinity是什么?搜一下发现在PackageParser.java里面:

private boolean parseBaseApplication(Package owner, Resources res,        XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)... ...ai.taskAffinity = buildTaskAffinityName(ai.packageName, ai.packageName,          str, outError);... ...}private static String buildCompoundName(String pkg,CharSequence procSeq, String type, String[] outError) {String proc = procSeq.toString();char c = proc.charAt(0);if (pkg != null && c == ':') {    ... ...    }    return proc.intern();}

很清楚了,默认的taskAffinity就是packageName,也就是com.taobao.taobao

这个Stringintern()方法又是个知识点,目的是节省空间:
调用s.intern()方法的时候,会将共享池中的字符串与外部的字符串(s)进行比较,如果共享池中有与之相等的字符串,则不会将外部的字符串放到共享池中的,返回的只是共享池中的字符串,如果不同则将外部字符串放入共享池中,并返回其字符串的句柄(引用)。

0 0