2018-10-25 Activity的启动流程

1.Activity的启动流程 不是Activity的生命周期,什么都不说先来看张图了解一下
1869462-882b8e0470adf85a.jpg
一.桌面应用图标被点击后发生的事情,大致分为几个流程

(1)APP的启动首先需要的是创建出Application的初始化创建。
1.Mian方法(JAVA的入门的方法)。
实例化ActivityThread 这个类
创建一个 Looper的轮训器作用是等待消息去创建Application,
thread.attach(false),这个方法为了Application的初始化做准备的。

 public static void main(String[] args){ 
 ... Looper.prepareMainLooper(); 
   //初始化
Looper ... ActivityThread thread = new ActivityThread();
//实例化一个
 ActivityThread thread.attach(false); 
 //这个方法最后就是为了发送出创建Application的消息 
 ... Looper.loop(); 
 //主线程进入无限循环状态,等待接收消息 
 }

2.attach方法的执行所做的事情。
上面提到过,ActivityThread的attach()方法最终的目的是发送出一条创建Application的消息——H.BIND_APPLICATION,到主线程的主Handler中。那我们来看看attach()方法干了啥。
ActivityManagerNative.getDefault();这个静态方法所做的一些操作是初始化准备的关键性的操作

public void attach(boolean system){ 
... final IActivityManager mgr = ActivityManagerNative.getDefault(); 
//获得IActivityManager实例,下面会看看它是个啥 
try { mgr.attachApplication(mAppThread); 
//看见没?关键啊。
mAppThread这个参数下面也会说一下 
} catch (RemoteException ex) 
{ 
throw ex.rethrowFromSystemServer(); 
} 
...
 }

IActivityManager mgr是个啥?

从上图也可以看到,IActivityManager是一个接口,当我们调用ActivityManagerNative.getDefault()获得的实际是一个代理类的实例——ActivityManagerProxy,这个东西实现了IActivityManager接口。打开源码你会发现,ActivityManagerProxy是ActivityManagerNative的一个内部类。可以看出,Android团队在设计的过程中是实践了最小惊异原则的,就是把相关的东西尽量放在一起。那么既然是个代理类,它究竟代理了谁?代码里看看喽。
在这里我直接将三段代码粘起来 (我的理解是:就是为了让ActivityManager获取IBinder 这个事例 )

在这里为了好理解 稍微扯远一点aidl 服务端创建一个Service 制定好aidl文件的中的方法,服务端创建一个server和aidl文件 创建Server创建的时候绑定aidi的文件的事例类 和实现下面的那些方法,这就是服务端要做的代码 ,在客户端需要做的就是,先启动服务端的server,在根据ServiceConnection这个类的回调的回来 获取(其实根据server的获取aidl的实现类对象,从而调用服务端的方法的)。这里只是一个aidi的简单的解释。

这里是通过ServiceManager获取到IBinder实例的。如果你以前了解AIDL通讯流程的话。这可能比较好理解一点,这只是通过另一种方式获取IBinder实例罢了。获取IBinder的目的就是为了通过这个IBinder和ActivityManager进行通讯,进而ActivityManager会调度发送H.BIND_APPLICATION即初始化Application的Message消息。

      public ActivityManagerProxy(IBinder remote) {
        mRemote = remote;
}
----------华丽的分割线-------------------

static public IActivityManager asInterface(IBinder obj) { 
 if (obj == null) {
 return null;
 } 
IActivityManager in = (IActivityManager)obj.queryLocalInterface(descriptor); /
/先检查一下有没有
 if (in != null) { 
return in; 
} ... 
return new ActivityManagerProxy(obj); 
//这个地方调用了构造函数 }
----华丽的分割线------
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() { 
protected IActivityManager create() { 
IBinder b = ServiceManager.getService("activity"); 
//重点啊!IBinder实例就是在这里获得的。 ... 
IActivityManager am = asInterface(b); 
//调用了上面的方法。 ...
 return am; 
} 
};
----华丽的分割线------
public void attachApplication(IApplicationThread app){
  ...
  mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);  
  ...
}
这个方法我在上图中也体现出来了。
这个方法中上面这一句是关键。调用了IBinder实例的tansact()方法,并且把参数app(这个参数稍后就会提到)放到了data中,最终传递给ActivityManager。
现在,我们已经基本知道了IActivityManager是个什么东东了。其实最重要的就是它的一个实现类ActivityManagerProxy,它主要代理了内核中与ActivityManager通讯的Binder实例。

ApplicationThread mAppThread又是个啥?

IApplicationThread是继承了IInterface的一个接口,我们需要关注一下里面的descriptor参数。后面会用它,它是一个标识,查询的时候很重要。
好,我们终于知道attach()方法中出现的两个对象是啥了。ApplicationThread作为IApplicationThread的一个实例,承担了最后发送Activity生命周期、及其它一些消息的任务。也就是说,前面绕了一大圈,最后还是回到这个地方来发送消息。我擦!
也许你会想,既然在ActivityThread中我们已经创建出了ApllicationThread的了,为什么还要绕这么弯路?,当然是为了让系统根据情况来控制这个过程喽,不然为什么要把ApplicationThread传到ActivityManager中呢?
到这里就是application的初始化已经做完了,下来就是给main方法中的looper发送一个消息 开始初始化application

ActivityManagerService调度发送初始化消息

private final boolean attachApplicationLocked(IApplicationThread thread
, int pid) {
    ...
    thread.bindApplication();
    //注意啦!
    ...
}
华丽的分割线-----------
public final void bindApplication(
  String processName, 
  ApplicationInfo appInfo, 
  List<ProviderInfo> providers,
   ComponentName instrumentationName,
   ProfilerInfo profilerInfo,
   Bundle instrumentationArgs, 
  IInstrumentationWatcher instrumentationWatcher, 
  IUiAutomationConnection instrumentationUiConnection, 
  int debugMode,
   boolean enableBinderTracking, 
  boolean trackAllocation, 
  boolean isRestrictedBackupMode, 
  boolean persistent, 
  Configuration config, 
  CompatibilityInfo compatInfo, 
  Map<String, IBinder> services, 
  Bundle coreSettings){
 ... sendMessage(H.BIND_APPLICATION, data); 
}

重点来了  初始化的方法
private void handleBindApplication(AppBindData data) { 
... mInstrumentation = (Instrumentation) cl.loadClass(data.instrumentationName.getClassName()) .newInstance();
 //通过反射初始化一个Instrumentation仪表。后面会介绍。 
... Application app = data.info.makeApplication(data.restrictedBackupMode, null); 
//通过LoadedApp命令创建Application实例
 mInitialApplication = app; 
... mInstrumentation.callApplicationOnCreate(app); /
/让仪器调用Application的onCreate()方法 ... }

Instrumentation仪表,什么鬼?(重点了 这个类初始化llication和activity都需要的)

1.这个叫Instrumentation仪表的东西十分诡异,姑且翻译为仪器吧。字面上看不出任何它是干什么的线索。但是,我们可以打开文档看看喽。
Instrumentation会在应用程序的任何代码运行之前被实例化,它能够允许你监视应用程序和系统的所有交互。
大概就这个意思啦。
2.但是,从上面的代码我们可以看出,Instrumentation确实是在Application初始化之前就被创建了。那么它是如何实现监视应用程序和系统交互的呢?
打开这个类你可以发现,最终Apllication的创建,Activity的创建,以及生命周期都会经过这个对象去执行。简单点说,就是把这些操作包装了一层。通过操作Instrumentation进而实现上述的功能。
3.那么这样做究竟有什么好处呢?仔细想想。Instrumentation作为抽象,当我们约定好需要实现的功能之后,我们只需要给Instrumentation仪表添加这些抽象功能,然后调用就好。剩下的,不管怎么实现这些功能,都交给Instrumentation仪器的实现对象就好。啊!这是多态的运用。啊!这是依赖抽象,不依赖具体的实践。啊!这是上层提出需求,底层定义接口,即依赖倒置原则的践行。呵!抽象不过如此。
从代码中可以看到,这里实例化Instrumentation的方法是反射!而反射的ClassName是来自于从ActivityManagerService中传过来的Binder的。套路太深!就是为了隐藏具体的实现对象。但是这样耦合性会很低。
4.好了,不瞎扯了。既然在说Instrumentation,那就看看最后调的callApplicationOnCreate()方法。

public void callApplicationOnCreate(Application app) {
    app.onCreate();
}

LoadedApk就是data.info哦!

public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {
 ... String appClass = mApplicationInfo.className; 
//Application的类名。明显是要用反射了。
 ... ContextImpl appContext = ContextImpl.createAppContext(mActivityThread , this); 
//留意下
Context app = mActivityThread.mInstrumentation .newApplication( cl, appClass, appContext); 
//通过仪表创建Application ...
 }
newApplication的方法
static public Application newApplication(Class<?> clazz , Context context) 
throws InstantiationException , 
IllegalAccessException ,
 ClassNotFoundException {
 Application app = (Application)clazz.newInstance(); //反射创建,简单粗暴 app.attach(context);
 //关注下这里,Application被创建后第一个调用的方法。 //目的是为了绑定Context。 return app; }

第一部分到这里已经全部结束了 下来是创建Activity 的过程

LaunchActivity

当Application初始化完成后,系统会更具Manifests中的配置的启动Activity发送一个Intent去启动相应的Activity
1.直接的,H就收到了一条LAUNCH_ACTIVITY的消息。然后开始初始化Activity之旅。收到消息后,真正处理是在ActivityThread中的handleLaunchActivity()中进行的
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();
        mSomeActivitiesChanged = true;
        if (r.profilerInfo != null) {
            mProfiler.setProfiler(r.profilerInfo);
            mProfiler.startProfiling();
        }    
        handleConfigurationChanged(null, null);
        if (localLOGV) Slog.v(
            TAG, "Handling launch of " + r);
        if (!ThreadedRenderer.sRendererDisabled) {
            GraphicsEnvironment.earlyInitEGL();
        }
        WindowManagerGlobal.initialize();
        Activity a = performLaunchActivity(r, customIntent);
        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            reportSizeConfigurations(r);
            Bundle oldState = r.state;
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
            if (!r.activity.mFinished && r.startsNotResumed) {
                performPauseActivityIfNeeded(r, reason);
                if (r.isPreHoneycomb()) {
                    r.state = oldState;
                }
            }
        } else {
            // If there was an error, for any reason, tell the activity manager to stop us.
            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) { 
... activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent);
//通过仪表来创建Activity ... Application app = r.packageInfo.makeApplication(false , mInstrumentation); 
//前面说过,是在获取Application
 ... activity.attach(
appContext , 
this ,
 getInstrumentation() , 
r.token ,
.ident ,
 app , 
r.intent , r.activityInfo ,
 title ,
 r.parent ,
 r.embeddedID , 
r.lastNonConfigurationInstances , 
config ,
r.referrer , r.voiceInteractor , window); //方法怪出现! ... if (r.isPersistable()) { mInstrumentation.callActivityOnCreate( activity, r.state, r.persistentState); }
else {
 mInstrumentation.callActivityOnCreate(activity, r.state); }
 //根据是否可持久化选择onCreate()方法。... }


public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException , IllegalAccessException, ClassNotFoundException { return (Activity)cl.loadClass(className).newInstance(); //真的没干啥。反射实例化Activity而已 }
if (r.isPersistable()) { mInstrumentation.callActivityOnCreate( activity, r.state, r.persistentState); } else { mInstrumentation.callActivityOnCreate(activity, r.state); }
onCreate(icicle, persistentState);
//可获得持久化数据
onCreate(icicle);
//平时重写的最多的。

好了 到了这里 activity的启动就写完了 根据主线一直跟下去 就可以发现他的实现方法 主要是在细节的发现。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容