Android四大组件之 Activity

在Android的四大组件之中相信最常用的就是Activity,相信每一个App或多或少都要有Activity的存在,几乎所有用户的交互方式都是通过Activity进行的,因此Activity类需要创建窗口通过setContentView方法来显示界面。当然现在的大屏设备以及更加复杂的用户界面也需要应用到Fragment这种片段类的方式来参与构建,但是作为今天的主角我们要从多方面的角度来分析Activity这个重要的组件。

Activity的生命周期

在系统活动中Activity被一种activity stack(栈)管理着,当一个新的Activity启动时,它被放置在堆栈的顶部成为活动的Activity,之前的Activity会始终保持位于新的Activity堆栈之下,而不会再次到达前台,直到新的Activity退出前台。Activity一般存在四种状态

四种状态

  1. 活动状态
    如果Activity是在屏幕最前端显示(在堆栈的顶部)时,它是活动的或称之为运行的。
  2. 暂停状态
    如果Activity已失去焦点,但仍清晰可见(即一个新的非全尺寸或透明的Activity或dialog集中在你的Activity上面)则暂停。一个暂停的Activity是完全活着(它保持所有的状态和信息,并保持连接在窗口管理器window manager上),但是在系统极端低内存的情况下会被杀死。
  3. 隐藏状态
    如果Activity完全被另一个Activity遮蔽,那它就停止了。它仍然保留所有的状态和成员信息,但是它不再对用户可见,所以它的窗口是隐藏的,它有时会因系统其他地方需要内存而被杀死。
  4. 停止状态
    如果Activity暂停或停止,系统可以通过finish方式将其从内存中清除,或者干脆杀死它的进程。当Activity重新启动时,它必须重新按照流程启动恢复到原来的状态。

让我们来关注一下Activity的生命周期,这样更容易理解以上所说的四种状态,Activity生命周期可以分为正常的生命周期(用户参与情况下)和异常的生命周期(系统回收或者当前设备的Configuration发生改变导致Activity销毁重建),两种情况会有所不同。

生命周期

以下是Google官方文档提供的生命周期图
activity生命周期图

我们可以在三个关键期间做一些文章

  • 由onCreate创建并最终由onDestroy销毁期间,Activity的onCreate方法具有“全局性”的设置,比如开启一个新的线程,相应的可以在onDestroy中停止这些启动的线程,来完结整个生命周期。
  • 由onStart开启直到相应onStop结束期间,此时Activity已经形成,但是还看不见,这里我们可以做相应的UI处理,比如注册一个广播onStart中来监控操作,然后改动UI变化,然后在onStop中销毁这个广播。
  • 由onResume到相应onPause期间短暂的时间里,重视的是用户和界面之间的交互代表着Activity已经位于前台,这一期间会频繁发生,如新的Intent传递,设备进入睡眠状态等,所以这里的代码要比较轻巧。
    然后我们来说一下生命周期


1. 正常情况下的生命周期
onCreate:表示Activity正在被创建,这个方法中,我们可以做一些全局初始化工作,入setContentView,初始化Activity所需要的数据等。

onStart:表示Activity正在启动,即将开始,这是Activity已可见,但是还没出现在前台,无法交互,我们还看不见。

onResume:表示Activity已经可见了,已在前台开始活动了,onResume重要的标志是Activity位于了前台(用户已可见)。

onPause:这个部分很重要,表示Activity正在停止,紧接着onStop就会调用,这里可以做一些存贮数据(数据持久化)停止动画等工作,注意不要太耗时,会影响到新的Activity的显示,因为onPause需要先执行,新Activity的onResume才能执行,这点要注意一下。

onStop:表示Activity即将停止,可以做一些稍微多一些的回收工作,同样不要太耗时。另如果当前Activity采用透明主题,切换Activity或点击Home键时不会回到此方法。

onDestroy:这里代表销毁Activity,做一些最终资源的释放,这一步骤的发生往往是人为做了finish处理或因为系统为了节约空间暂时性销毁,可以通过isFinish方法区别这两种情况。

onRestart:表示Activity重新启动,由隐藏变为活动状态(见上面四种状态)时所回调的方法,比如用户点击Home键或打开新的Activity造成onStop执行,然后回到这个界面产生的回调。

2. 异常情况下的生命周期
Activity可能会由于内存资源不足或者系统配置发生变化导致Activity被杀死并重新创建,因为一旦配置改变,则任何显示用户界面将需要更新以匹配新的配置,比如旋转屏幕方向等。 但是在这个过程中,系统会调用onSaveInstanceState来保存当前Activity的状态,注意这个方法调用时机是在onStop之前和onPause没有既定的顺序。这个回调只会发生在异常的生命周期情况下,再重新创建后系统会调用onRestoreInstanceState将之前保存到Bundle信息传给RestoreInstanceState和onCreate方法,因此,我们可以通过onRestoreInstanceState和onCreate方法来判断Activity是否被重建了,onRestoreInstanceState会在onStart之后执行。
对于数据恢复这部分,系统的View也帮我们做了一些工作,每个View也有自己的onSaveInstanceState和onRestoreInstanceState这两个方法。
下面我们做一个例子,用转动屏幕的方式来看一下View的数据存贮恢复和我们自己的数据存贮恢复情况:

public class MainActivity extends ActionBarActivity {

    private final static String TAG = "myTag";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (savedInstanceState != null) {
            Log.d(TAG, "oncreate:" + savedInstanceState.getString("data"));
        }
    }

    @Override
    public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);
        Log.d(TAG, "onSaveInstanceState");
        outState.putString("data", "test_entity");
    }

    @Override
    protected void onStart() {
        super.onStart();
        Log.d(TAG, "onStart");
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.d(TAG, "onRestoreInstanceState:" + savedInstanceState.getString("data"));
    }
}

这两种接收方式都可以,官方推荐使用onRestoreInstanceState方法,他们的区别在于onCreate方法中无法自行鉴别Bundle是否有值需要判断,而onRestoreInstanceState不用。我们可以看一下方法执行的效果。
View的存贮 Activity的存贮
看以看到我们输入的文字在经过屏幕变化后还是显示的,我们的Log信息也有显示,可见,Android系统的View和我们对数据的恢复都起了作用。
当Android资源内存资源内存不足时也会导致低优先级的Activity被杀死,状态越靠前优先级越高(见前面Android四种状态)。同样系统同样会后续通过onSaveInstanceState和onRestoreInstanceState来存贮和恢复数据,如果一个进程没有四大组件在执行,那么这个进程将很快被系统杀死,因此一些后台工作要依赖四大组件运行,可以用Service保证优先级,关于Service 我们会后期分析。当然我们可以可以人为的控制系统配置,让其不进行重新创建。就是指定configChanges属性,比如禁止旋转屏幕且隐藏键盘

android:configChanges=”orientation|keyboardHidden”;

这样就可以了,因为configChanges属性变化就会导致Activity重新创建,所以我们可以人为控制:
config

配置后代码类似下面这样:

<activity
    android:name=".MainActivity"
    android:configChanges="keyboardHidden|orientation">
        <intent-filter>
             <action android:name="android.intent.action.MAIN" />
             <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
</activity>

Activity的启动模式

接下来我们来说一下Activity的启动模式,Activity默认启动后会放在activity stack的顶部,多次创建同一个Activity会产生多个对象,当我们点击back键时,会发现有多个同一个Activity的效果。有些时候这并不是我们想要到效果。那么我们就要通过Activity的启动模式来控制Activity的启动方式,如何使用呢只需要配置launchMode就好

<activity
    android:name=".SingleTaskActivity"
    android:label="singleTask launchMode"
    android:launchMode="singleTask|standard|singTop|singleInstance">
</activity>

或者通过Intent设置,比如:

 Intent intent = new Intent(); 
 intent.setClass(MainActivity.this,SecondActivity.class);
 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
 startActivity(intent);

优先级通过Intent设置要高于清单文件中,Intent方式无法设定一种模式,而是一种启动方式,让我们来看一下这些常用的标记位Flags:

FLAG_ACTIVITY_SINGLE_TOP
和Activity的Launch mode的singleTop类似。如果某个intent添加了这个标志,并且这个intent的目标activity就是栈顶的activity,那么将不会新建一个实例压入栈中,如果目标activity已在栈顶则不出创建新的activity。

FLAG_ACTIVITY_CLEAR_TOP
例如现在的栈情况为:A B C D 。D此时通过intent跳转到B,如果这个intent添加FLAG_ACTIVITY_CLEAR_TOP标记,则栈情况变为:A B。如果没有添加这个标记,则栈情况将会变成:A B C D B。这跟上面把B的Launch mode设置成singleTask类似。简而言之,跳转到的activity若已在栈中存在,则将其上的activity都销掉。

FLAG_ACTIVITY_NEW_TASK
例如现在栈1的情况是:A B C。C通过intent跳转到D,并且这个intent添加了FLAG_ACTIVITY_NEW_TASK标记,如果D这个Activity在Manifest.xml的声明中添加了Task affinity,系统首先会查找有没有和D的Task affinity相同的task栈存在,如果有存在,将D压入那个栈,如果不存在则会新建一个D的affinity的栈将其压入。如果D的Task affinity默认没有设置,则会把其压入栈1,变成:A B C D,这样就和不加FLAG_ACTIVITY_NEW_TASK标记效果是一样的了。效果和“singleTask”相同。

FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
如果设置,新的Activity不会在最近启动的Activity的列表中保存。等同于在xml实现android:excludeFromRecents=”true”。

standard模式

标准模式,也是系统默认的模式,每次启动都会生成一个Activity对象,在这种模式下,谁启动了这个Activity那么这个Activity就会运行在启动这个Activity所在的栈中。当我们用ApplicationContext启动standard模式的Activity时会报错,因为非Activity的context没有任务栈就有了这种问题,可以采用其他模式启动。

singleTop模式

栈顶复用模式,如果Activity已经位于栈顶,就不会在为我们创建新的Activity,同时会回调onNewIntent方法,如果Activity存在但是不是位于栈顶,那么还是会创建的。只有在调用者和目标Activity在同一Task中,并且目标Activity位于栈顶,才会使用现有目标Activity实例,否则创建新的目标Activity实例。singleTop的应用场景很多,关于singleTop一个典型的使用场景就是搜索功能。假设有一个搜索框,每次搜索查询都会将我们引导至SearchActivity查看结果,为了更好的交互体验,我们在结果页顶部也放置这样的搜索框。假设一下,SearchActivity启动模式为standard,那么每一个搜索都会创建一个新的SearchActivity实例,10次查询就是10个Activity。当我们想要退回到非SearchActivity,我们需要按返回键10次,这显然太不合理了。

singleTask模式

栈内复用模式,只要在栈中存在这个Activity多次启动是不会再创建这个实例的,系统也会回调onNewIntent方法。当一个具有singleTask模式的Activity请求启动时,系统会寻找是否有Activity需要的任务栈,如果不存在就创建一个Activity所需的任务栈,然后把其放在栈中。如果存在这个任务栈,要看栈中是否有这个Activity,如果有,系统就会调用onNewIntent方法,把Activity调回栈顶并采用cleanTop方式,将Activity上的其他Activity全部出栈,如果没有则会创建一个实例压入栈中。同时我们也要谨慎使用这种模式,因为它可以在用户未感知的情况下销毁掉其他Activity。其实所需要的任务栈是通过TaskAffinity的参数指定的,默认情况下所有Activity所需要的任务栈名字和应用包名相同,TaskAffinity属性主要和singleTask启动模式和allowTaskReparenting属性配对使用,其他情况下没有意义,任务栈分为前台栈和后台栈,后台栈可以通过切换的方式调到前台。

singleInstance模式

单实例模式,是一种加强版的singTask模式,除了具有singleTask所有特性外,还加强了一点,那就是具有这种模式的Activity只能单独位于一个任务栈中。如果从singleInstance Activity实例启动另一个Activity,那么这个Activity实例会放入其他的Task中。同理,如果singleInstance Activity被别的Activity启动,它也会放入不同于调用者的Task中。由于栈内复用的特性,后续的请求不会创建新的Activity。


IntentFilter的匹配规则

下面我们来说一下Intent在Activity的匹配规则,Android中启动Activity分为显示和隐示两种方式,原则上Intent不会既是显示又是隐示,如果出现以显示为准。显示调用通过startActivity就可以进行,隐示调用一般更加灵活,下面我们来看一下通过Activity中的IntentFilter过滤信息设置来进行隐式调用。过滤信息包含着action、category和data。一个Activity可以含有多个intent-filter,一个Intent只要匹配一个intent-filter就可以成功的找到对应的Activity,下面我们详细说一下每一个过滤信息。

action

一个过滤中可以有多个action,同时我们也可以在应用中定义自己的action,如果Intent中没有指定action那么匹配会失败,所以intent中至少有1个action,而且intent中不能包含过滤中没有的action,还要注意action中大小写是有区分的。

匹配规则:action的匹配,要求是Intent中至少含有一个action,且这一个或多个action能在过滤规则中找到相同的action

category

category和action不同,在Intent中可以没有category(系统会默认添加),如果含有category那么所有的category必须和过滤规则中的其中一个category相同,其实系统在调用startActivity和startActivityForResult时候会默认为Intent加上”android.intent.category.DEFAULT”这个category。注意,如果你想隐式启动某个组件,那么就得在IntentFilter中添加”android.intent.category.DEFAULT”这个category才行,因为系统会默认给Intent设置default标签的。

匹配规则:category要求Intent中可以没有category(其实是系统已经默认添加),但是你一旦有category,不管几个,每个都要和IntentFilter中的category相同

data

data由mimeType和URI组成,mimeType代表媒体类型,比如audio、jpeg可以表示图片、文本、视频等不同的媒体格式。URI指资源地址,结构如下:

< scheme >: // < host >:< port >/ [< path > | < pathPattern >]

scheme:访问资源的命名机制,比如http、content等,没有模式整个URI无效。
host+post:存放资源的主机名和端口号。
path | pathPatern:资源自身的名称,由路径表示,其中pathPatern表示带有通配符。
data的匹配方式和action类似,如果过滤条件中有data那么intent中也要有且能匹配过滤条件中的数据,data中是要能够完全匹配,即intent中的data部分也出现在了过滤条件中
注意!如果intent-filter中是:

< data android:mimeType=”image/*” />

那么指定为图片类型,这种情况下虽然没有指定URI,但是却有默认值,是content和file。也就是说,虽然没有URI但是intent的URI部分的schema必须为content或者是file才能匹配。 还有如果为Intent指定完整的data,必须调用setDataAndType方法,先后调用setData和setType会造成彼此消除对方,从源码中可以看出来。

匹配规则:如果IntentFilter中有定义data,那么Intent中也必须至少含有其中的一个data信息与data是匹配的


下面我们举一个相互匹配的例子来看看intentFilter如何使用(如果不匹配的话跳转会发生crash,抛出异常):

<intent-filter>
     <action android:name="android.intent.action.SEND" />
     <action android:name="com.my.data" />

     <category android:name="android.intent.category.DEFAULT" />
     <category android:name="com.my.category1" />
     <category android:name="com.my.category2" />

     <data
         android:scheme="http"
         android:host="hkx"
         android:port="11"
         android:path="/abc"
         android:mimeType="video/*"/>
     <data
         android:path="/dd/b"
         android:scheme="content" />
     <data android:mimeType="image/*" />
</intent-filter>

相匹配的intent设置方式如下:

     Intent intent = new Intent();
     intent.setAction("com.my.data");//至少有一个,且只要能匹配到过滤中的一个
//   intent.setAction("android.intent.action.SEND");//可以不囊括过滤中所有的action
//   intent.setAction("com.my.nodata");//不能含有过滤中没有的action

     intent.addCategory("android.intent.category.DEFAULT");//这个是默认的categroy可以不写(不写也会有)
     intent.addCategory("com.my.category1");//过滤规则中必须有这个category
//   intent.addCategory("com.my.category2");//可以不全囊括过滤中所有的category
//   intent.addCategory("com.my.noategory");//不能含有过滤中没有的category

     intent.setDataAndType(Uri.parse("http://hkx:11/abc"), "video/*");//是过滤中的信息
     intent.setDataAndType(Uri.parse("http://hkx:11/cba"), "image/*");//是过滤中的信息
     intent.setDataAndType(Uri.parse("http://hkx:11/abc"), "image/*");//是过滤中的信息 这样写也可以对比上面 
     intent.setDataAndType(Uri.parse("http://hkx:11/cba"), "video/*");//是过滤中的信息 这样写也可以对比上面 
     startActivity(intent);

最后我们说明一下:有一类action和category非常重要:

< action android:name=”android.intent.action.MAIN” />
< category android:name=”android.intent.category.LAUNCHER” />

这两个表示了这是一个入口Activity并且会出现在系统列表中,两个中少了任何一个都没有意义,Service、BroadCastReceiver也有这些类似方法去获取匹配信息。


Activity的工作过程

在调用方式上来说,Activity和Service与BroadCastReceiver一样都需要Intent,由于系统对Activity的启动流程已经帮助我们进行了封装,所以我们一般不是很关注这一点,我们只需要调用startActivity就可以启动一个Activity,那么系统对Activity启动是如何实现的呢,这个Activity的底层是如何实现的呢?下面我们来简单探讨一下
我们看一下startActivity这个启动的方法

 public void startActivityForResult(Intent intent, int requestCode) {
        startActivityForResult(intent, requestCode, null);
 }
@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);
        }
  }

可以看到最它们都调用了startActivityForResult方法。那么下面我们看一看这个方法又是什么

    public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
        // 这里的mParent是ActivityGroup,已被废弃,所以一般activity这个值为空
        if (mParent == null) {
            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) {
                // 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.
                mStartedActivity = true;
            }

            final View decor = mWindow != null ? mWindow.peekDecorView() : null;
            if (decor != null) {
                decor.cancelPendingInputEvents();
            }
            // TODO Consider clearing/flushing other event sources and events for child windows.
        } else {
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                // Note we want to go through this method for compatibility with
                // existing applications that may have overridden it.
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
        if (options != null && !isTopOfTask()) {
            mActivityTransitionState.startExitOutTransition(this, options);
        }
    }

我们可以看到mInstrumentation.execStartActivity方法是启动这个activity的真正方法。我们再来看一下这个启动过程

   public ActivityResult execStartActivity(  
        Context who, IBinder contextThread, IBinder token, Activity target,  
        Intent intent, int requestCode, Bundle options) {  
    //核心功能在这个whoThread中完成,其内部scheduleLaunchActivity方法用于完成activity的打开  
    IApplicationThread whoThread = (IApplicationThread) contextThread;  
    if (mActivityMonitors != null) {  
        synchronized (mSync) {  
            //先查找一遍看是否存在这个activity  
            final int N = mActivityMonitors.size();  
            for (int i=0; i<N; i++) {  
                final ActivityMonitor am = mActivityMonitors.get(i);  
                if (am.match(who, null, intent)) {  
                    //如果找到了就跳出循环  
                    am.mHits++;  
                    //如果目标activity无法打开,直接return  
                    if (am.isBlocking()) {  
                        return requestCode >= 0 ? am.getResult() : null;  
                    }  
                    break;  
                }  
            }  
        }  
    }  
    try {  
        intent.migrateExtraStreamToClipData();  
        intent.prepareToLeaveProcess();  
        //这里才是真正打开activity的地方,核心功能在whoThread中完成。  
        int result = ActivityManagerNative.getDefault()  
            .startActivity(whoThread, who.getBasePackageName(), intent,  
                    intent.resolveTypeIfNeeded(who.getContentResolver()),  
                    token, target != null ? target.mEmbeddedID : null,  
                    requestCode, 0, null, null, options);  
        //这个方法是专门抛异常的,它会对结果进行检查,如果无法打开activity,  
        //则抛出诸如ActivityNotFoundException类似的各种异常  
        checkStartActivityResult(result, intent);  
    } catch (RemoteException e) {  
    }  
    return null;  
}  

接下来我们要去看下IApplicationThread,因为核心功能由其内部的scheduleLaunchActivity方法来完成

public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,  
        ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,  
        int procState, Bundle state, List<ResultInfo> pendingResults,  
        List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,  
        String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {  

    updateProcessState(procState, false);  

    ActivityClientRecord r = new ActivityClientRecord();  

    r.token = token;  
    r.ident = ident;  
    r.intent = intent;  
    r.activityInfo = info;  
    r.compatInfo = compatInfo;  
    r.state = state;  

    r.pendingResults = pendingResults;  
    r.pendingIntents = pendingNewIntents;  

    r.startsNotResumed = notResumed;  
    r.isForward = isForward;  

    r.profileFile = profileName;  
    r.profileFd = profileFd;  
    r.autoStopProfiler = autoStopProfiler;  

    updatePendingConfiguration(curConfig);  

    queueOrSendMessage(H.LAUNCH_ACTIVITY, r);  
}  

构造一个activity记录,然后发送一个消息,所以,我们要看看Handler是如何处理这个消息的,现在转到这个Handler,它有个很短的名字叫做H

private class H extends Handler {  

    public void handleMessage(Message msg) {  
        if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));  
        switch (msg.what) {  
            //这里处理LAUNCH_ACTIVITY消息类型  
            case LAUNCH_ACTIVITY: {  
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");  
                ActivityClientRecord r = (ActivityClientRecord)msg.obj;  

                r.packageInfo = getPackageInfoNoCheck(  
                        r.activityInfo.applicationInfo, r.compatInfo);  
                //这里处理startActivity消息  
                handleLaunchActivity(r, null);  
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);  
            } break;  
            case RELAUNCH_ACTIVITY: {  
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");  
                ActivityClientRecord r = (ActivityClientRecord)msg.obj;  
                handleRelaunchActivity(r);  
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);  
            } break;  
            case PAUSE_ACTIVITY:  
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");  
                handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);  
                maybeSnapshot();  
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);  
                break;  
            ...  
        }  
}  

下面看最后一个方法,这个方法是activity的启动过程的真正实现。

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {  
    // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");  

    ActivityInfo aInfo = r.activityInfo;  
    if (r.packageInfo == null) {  
        r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,  
                Context.CONTEXT_INCLUDE_CODE);  
    }  
    //首先从intent中解析出目标activity的启动参数  
    ComponentName component = r.intent.getComponent();  
    if (component == null) {  
        component = r.intent.resolveActivity(  
            mInitialApplication.getPackageManager());  
        r.intent.setComponent(component);  
    }  

    if (r.activityInfo.targetActivity != null) {  
        component = new ComponentName(r.activityInfo.packageName,  
                r.activityInfo.targetActivity);  
    }  

    Activity activity = null;  
    try {  
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();  
        //用ClassLoader(类加载器)将目标activity的类通过类名加载进来并调用newInstance来实例化一个对象  
        //其实就是通过Activity的无参构造方法来new一个对象,对象就是在这里new出来的。  
        activity = mInstrumentation.newActivity(  
                cl, component.getClassName(), r.intent);  
        StrictMode.incrementExpectedActivityCount(activity.getClass());  
        r.intent.setExtrasClassLoader(cl);  
        if (r.state != null) {  
            r.state.setClassLoader(cl);  
        }  
    } catch (Exception e) {  
        if (!mInstrumentation.onException(activity, e)) {  
            throw new RuntimeException(  
                "Unable to instantiate activity " + component  
                + ": " + e.toString(), e);  
        }  
    }  

    try {  
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);  

        if (localLOGV) Slog.v(TAG, "Performing launch of " + r);  
        if (localLOGV) Slog.v(  
                TAG, r + ": app=" + app  
                + ", appName=" + app.getPackageName()  
                + ", pkg=" + r.packageInfo.getPackageName()  
                + ", comp=" + r.intent.getComponent().toShortString()  
                + ", dir=" + r.packageInfo.getAppDir());  

        if (activity != null) {  
            Context appContext = createBaseContextForActivity(r, activity);  
            CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());  
            Configuration config = new Configuration(mCompatConfiguration);  
            if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "  
                    + r.activityInfo.name + " with config " + config);  
            activity.attach(appContext, this, getInstrumentation(), r.token,  
                    r.ident, app, r.intent, r.activityInfo, title, r.parent,  
                    r.embeddedID, r.lastNonConfigurationInstances, config);  

            if (customIntent != null) {  
                activity.mIntent = customIntent;  
            }  
            r.lastNonConfigurationInstances = null;  
            activity.mStartedActivity = false;  
            int theme = r.activityInfo.getThemeResource()  
            if (theme != 0) {  
                activity.setTheme(theme);  
            }  

            activity.mCalled = false;  
            //目标activity的onCreate被调用了,到此为止,Activity被启动了,接下来的流程就是Activity的生命周期了,  
            //本文之前已经提到,其生命周期的各种状态的切换由ApplicationThread内部来完成  
            mInstrumentation.callActivityOnCreate(activity, r.state);  
            if (!activity.mCalled) {  
                throw new SuperNotCalledException(  
                    "Activity " + r.intent.getComponent().toShortString() +  
                    " did not call through to super.onCreate()");  
            }  
            r.activity = activity;  
            r.stopped = true;  
            if (!r.activity.mFinished) {  
                activity.performStart();  
                r.stopped = false;  
            }  
            if (!r.activity.mFinished) {  
                if (r.state != null) {  
                    mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);  
                }  
            }  
            if (!r.activity.mFinished) {  
                activity.mCalled = false;  
                mInstrumentation.callActivityOnPostCreate(activity, r.state);  
                if (!activity.mCalled) {  
                    throw new SuperNotCalledException(  
                        "Activity " + r.intent.getComponent().toShortString() +  
                        " did not call through to super.onPostCreate()");  
                }  
            }  
        }  
        r.paused = true;  

        mActivities.put(r.token, r);  

    } catch (SuperNotCalledException e) {  
        throw e;  

    } catch (Exception e) {  
        if (!mInstrumentation.onException(activity, e)) {  
            throw new RuntimeException(  
                "Unable to start activity " + component  
                + ": " + e.toString(), e);  
        }  
    }  

    return activity;  
}  

ok,我们简单的分析了一下流程,由于系统其实对Activity启动处理比较复杂,如果深入研究还需要多涉猎一些资料。
说了这么多,我们对Activity的分析就暂且说到这里,可能不是很详细,希望对读者和自己日后有一些帮助吧 ~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值