《Android开发艺术探索》之学习笔记(九)四大组件的工作过程

四大组件概述

  • Activity,是一种展示型组件,用于向用户展示UI。它只有一种运行模式:处于启动状态。
  • Service,是一种计算型组件,用于在后台执行一系列计算任务。它有两种状态:启动状态和绑定状态。Service是运行在主线程的,因此耗时的任务需要在工作线程去完成。Service处于绑定状态时,它内部同样可以进行后台计算。
  • BroadCastReceiver,是一种消息行组件,用于在不同的组件甚至不同应用间传递消息。静态注册在应用安装时会被系统解析,不需要应用启动就能收到相应的广播;动态注册必须要应用启动后才能收到广播。
  • ContentProvider,是一种数据共享型组件,用于向其他组件甚至其他应用共享数据。它对数据集合的具体实现没有要求,可以是数据库,List、Map甚至文件等。它内部的insert、delete、update和query方法需要处理好线程同步,因为这几个方法是运行在Binder线程池中的。ContentProvider不需要手动停止。

Activity的工作过程

一张图说明Activity的启动流程:


这里写图片描述

performLaunchActivity这个方法主要完成如下几件事:
1、从ActivityClientRecord中获取待启动的Activity的组件信息

ActivityInfo aInfo = r.activityInfo;
if (r.packageInfo == null) {
   r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
           Context.CONTEXT_INCLUDE_CODE);
}

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);
}

2、通过Instrumention的newActivity方法使用类加载器创建Activity对象

Activity activity = null;
try {
    java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
    activity = mInstrumentation.newActivity(
            cl, component.getClassName(), r.intent);
    StrictMode.incrementExpectedActivityCount(activity.getClass());
    r.intent.setExtrasClassLoader(cl);
    r.intent.prepareToEnterProcess();
    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);
    }
}

3、通过LoadedApk的makeApplication方法来尝试创建Application对象
LoadedApk.calss被标记为@hide类,源码在sdk/sources/android-22/android/app目录下

public Application makeApplication(boolean forceDefaultAppClass,
        Instrumentation instrumentation) {
    if (mApplication != null) {
        return mApplication;
    }

    Application app = null;

    String appClass = mApplicationInfo.className;
    if (forceDefaultAppClass || (appClass == null)) {
        appClass = "android.app.Application";
    }

    try {
        java.lang.ClassLoader cl = getClassLoader();
        if (!mPackageName.equals("android")) {
            initializeJavaContextClassLoader();
        }
        ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
        app = mActivityThread.mInstrumentation.newApplication(
                cl, appClass, appContext);
        appContext.setOuterContext(app);
    } catch (Exception e) {
        if (!mActivityThread.mInstrumentation.onException(app, e)) {
            throw new RuntimeException(
                "Unable to instantiate application " + appClass
                + ": " + e.toString(), e);
        }
    }
    mActivityThread.mAllApplications.add(app);
    mApplication = app;

    if (instrumentation != null) {
        try {
            instrumentation.callApplicationOnCreate(app);
        } catch (Exception e) {
            if (!instrumentation.onException(app, e)) {
                throw new RuntimeException(
                    "Unable to create application " + app.getClass().getName()
                    + ": " + e.toString(), e);
            }
        }
    }

    // Rewrite the R 'constants' for all library apks.
    SparseArray<String> packageIdentifiers = getAssets(mActivityThread)
            .getAssignedPackageIdentifiers();
    final int N = packageIdentifiers.size();
    for (int i = 0; i < N; i++) {
        final int id = packageIdentifiers.keyAt(i);
        if (id == 0x01 || id == 0x7f) {
            continue;
        }

        rewriteRValues(getClassLoader(), packageIdentifiers.valueAt(i), id);
    }

    return app;
}

Application创建完毕后,系统会通过Instrumention的callApplicationOncreate来调用Application的onCreate方法

4、创建ContextImpl对象并通过Activity发attach方法来完成一些重要数据的初始化
5、调用Activity的onCreate方法

Service的工作过程

Service的启动过程

一张图说明Service的启动流程:


这里写图片描述

handleCreateService方法主要完成如下几件事:
1、通过类加载器创建Service的实例
2、创建Application对象并调用其onCreate方法
3、创建ContextImpl对象并通过Service发attach方法建立二者之间的关系
4、调用Service的onCreate方法并将Service对象存储到ActivityThread中的一个列表中。ActivityThread通过handleServiceArgs方法调用Service的onStarCommand方法

Service的绑定过程

一张图说明Service的绑定过程:


这里写图片描述

handleBindService方法主要完成如下几件事:
1、根据Service的token取出Service对象,调用Service的onBind方法
2、通过ActivityManagerService调用publishService方法通知客户端已经成功连接Service

BroadcastReceiver的工作过程

Activity、Service、ContentProvider和BroadcastReceiver的静态注册都是在应用安装时由PackageManagerService解析注册的。

BroadcastReceiver的注册过程

这里写图片描述

BroadcastReceiver的发送和接收过程

自Android3.1开始,系统为Intent新增了两个标志,并为所有广播默认添加 FLAG_EXCLUDE_STOPPED_PACKAGES 标志,防止无意间或者在不必要的时候唤醒已经停止的APP,这个特性同样会影响开机广播

  • FLAG_INCLUDE_STOPPED_PACKAGES
    表示包含已经停止的APP,这个时候广播会发送到已经停止的APP
  • FLAG_EXCLUDE_STOPPED_PACKAGES
    表示不包含已经停止的APP,这个时候广播不会发送给已经停止的APP

当两个标志共存时,以 FLAG_INCLUDE_STOPPED_PACKAGES 为准

这里写图片描述

ContentProvider的工作过程

当ContentProvider所在的进程启动时,ContentProvider会同时启动并被发布到ActivityManagerService中,这个时候ContentProvider的onCreate要先于Application的onCreate执行

这里写图片描述

ActivityThread的handleBindApplication方法最终完成Application和ContentProvider的创建,步骤如下:

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

推荐阅读更多精彩内容