android28 Activity的创建过程

版本android28源码

继承关系总结:
Activity:ContextWrapper:Context
ContextImpl:Context(抽象类,实现在安卓框架)
ReceiverRestrictedContext:ContextWrapper
ActivityManagerNative(Deprecated,推荐直接使用ActivityManager方法了)

1 ActivityThread.main

ActivityThread是一个APP开始启动的地方,AMS通过反射调用ActivityThread的main函数,启动后准备好mainlooper,开始显式new ActivityThread();
ActivityThread内部的handler就开始运行,绑定到当前线程(主线程)
后面立马做了一个attach动作,做了一些和虚拟机有关的操作
(1).ViewRootImpl.addFirstDrawHandler{ensureJitEnabled()} 往ViewRootImpl的sFirstDrawHandlers的list里放入jvm初始化jit,在第一次draw的时候触发
(2).android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());//预设置进程名
(3).ActivityManager.attachApplication
(4).BinderInternal.addGcWatcher//用掉3/4的内存的时候,尝试释放一些activity
后续开启Looper.loop();永远在接收消息,主线程保持在阻塞状态,处理来自AMS的消息命令

ActivityClientRecord保存了一个activity的记录,包含生命周期等

/**  Core implementation of activity launch. */
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...}

新建流程

ActivityThread.java中有2个分支
handleRelaunchActivity->handleRelaunchActivityInner->handleLaunchActivity->performLaunchActivity
-startActivityNow()->performLaunchActivity()
startActivityNow新建了一个ActivityClientRecord对象包装了activity信息,来启动activity

performLaunchActivity中

1.mInstrumentation.newActivity //反射新建Activity 但是没有attach
2.Application app = r.packageInfo.makeApplication//新建并attach application 会调用app oncreate
3.activity.attach(进入app的activity内,新建PhoneWindow)
4.mInstrumentation.callActivityOnCreate(activity, r.state);//调用oncreate
5.在oncreate内固定调用setcontetview //安装decorview 添加layout

activity.attach的分析

final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback)

第一行attachBaseContext(context); 最终ContextWrapper 将context存入内部mBase
activity提供的getMainLooper等大多数功能都是从context来

ContextThemeWrapper.java中一个有意思的地方,LAYOUT_INFLATER_SERVICE是单例模式生成在ContextThemeWrapper中的

ContextThemeWrapper.java
@Override
    public Object getSystemService(String name) {//@1
        if (LAYOUT_INFLATER_SERVICE.equals(name)) {
            if (mInflater == null) {
                mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);//@3
            }
            return mInflater;
        }
        return getBaseContext().getSystemService(name);
    }

LayoutInflater.java
public static LayoutInflater from(Context context) {//@2
        LayoutInflater LayoutInflater =
                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        if (LayoutInflater == null) {
            throw new AssertionError("LayoutInflater not found.");
        }
        return LayoutInflater;
    }

LayoutInflater.from() 调用了2次,一般的入口是函数2,我主动调用的2
2内部调用1,1的内部也调用了LayoutInflater.from() 这个特殊调用称为3,3中的context是contextImp,所以getSystemService就不一样了
AndroidSDK\sources\android-28\android\app\SystemServiceRegistry.java

真正的LayoutInflater系统服务

 registerService(Context.LAYOUT_INFLATER_SERVICE, LayoutInflater.class,
                new CachedServiceFetcher<LayoutInflater>() {
            @Override
            public LayoutInflater createService(ContextImpl ctx) {
                return new PhoneLayoutInflater(ctx.getOuterContext());
            }});

PhoneLayoutInflater.java
public LayoutInflater cloneInContext(Context newContext) {
        return new PhoneLayoutInflater(this, newContext);
    }
protected PhoneLayoutInflater(LayoutInflater original, Context newContext) {
        super(original, newContext);
    }

LayoutInflater.java
protected LayoutInflater(LayoutInflater original, Context newContext) {
        mContext = newContext;
        mFactory = original.mFactory;
        mFactory2 = original.mFactory2;
        mPrivateFactory = original.mPrivateFactory;
        setFilter(original.mFilter);
    }

PhoneLayoutInflater存在的意义

1.就是用外部context新建了一个inflater 避免把factory映射到系统inflater的factory里
2.重载onCreateView,兼容以.开头的安卓内部控件(.button-》android.widget.等前缀)

PhoneWindow的新建

Activity的attach内第三行

mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);

Activity的setContentView过程

public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);//attach 创建的PhoneWindow
        initWindowDecorActionBar();
    }

window是代表窗口的抽象,只有唯一实现PhoneWindow

abstract class Window 
public class PhoneWindow extends Window implements MenuBuilder.Callback

PhoneWindow 中的setContentView

// This is the top-level view of the window, containing the window decor.
    private DecorView mDecor;
// This is the view in which the window contents are placed. It is either
    // mDecor itself, or a child of mDecor where the contents go.
    ViewGroup mContentParent;

 @Override
    public void setContentView(int layoutResID) {
        // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
        // decor, when theme attributes and the like are crystalized. Do not check the feature
        // before this happens.
        if (mContentParent == null) {
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }

        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                    getContext());
            transitionTo(newScene);
        } else {
            mLayoutInflater.inflate(layoutResID, mContentParent);
        }
        mContentParent.requestApplyInsets();
        final Callback cb = getCallback();
        if (cb != null && !isDestroyed()) {
            cb.onContentChanged();
        }
        mContentParentExplicitlySet = true;
    }

installDecor内

1.generateDecor 生成新DecorView到mDecor
2.mContentParent = generateLayout(mDecor);解析属性,生成layout

generateLayout中

1.R.layout.screen_custom_title里含有android.R.id.content
2.layoutResource = R.layout.screen_custom_title;
3.onResourcesLoaded(LayoutInflater inflater, int layoutResource)中DecorView添加layoutResource作为宽高都match_parent的子view
4.找到了ID_ANDROID_CONTENT 返回结果mContentParent

所以mContentParent 是我们添加布局的根节点
回到PhoneWindow 中的setContentView中
mLayoutInflater.inflate(layoutResID, mContentParent);终于将我们的布局加载到mContentParent下面了

activity
=外层PhoneWindow(Window的实现)
==DecorView(FrameLayout子类)
===mContentParent (ID_ANDROID_CONTENT,根布局)


image.png

图片的原始地址

oncreate只把layout安装上去,还没有开始显示layout

ActivityThread.java中
handleResumeActivity->performResumeActivity
handleNewIntent->performNewIntents->performResumeActivity

performResumeActivity中调用activity.performResume

1.performRestart(true /* start */, reason);//
2.mInstrumentation.callActivityOnResume(this);-》activity.onResume();

handleResumeActivity

@Override
    public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,String reason) {
...
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
...
final Activity a = r.activity;
...
View decor = r.window.getDecorView();
ViewManager wm = a.getWindowManager();
...
wm.addView(decor, l);//实际调用WindowManagerGlobal.addView,新建ViewRootImpl

PhoneWindow在新建后setWindowManager

mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);

WindowManager接口,实现在WindowManagerImpl

mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);

每一个Window在setWindowManager的时候从系统服务中新建一个WindowManagerImpl

public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mContext, parentWindow);
    }

重点就是parentWindow被设置为当前Window
所以activity中的getSystemService重载,对WINDOW_SERVICE返回mWindowManager(就是createLocalWindowManager新建的那个)
如果是在service里,getSystemService获得的是sysytem那个parentWindow为空的WindowManagerImpl。(补充:另外一个getSystemService重载的是SEARCH_SERVICE activity直接新建保存为内部变量了,没有用系统的,不知道为啥可能省略了一个入参handler的原因)

WindowManagerImpl的实际使用:代理模式代理\单例模式

private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();

WindowManagerGlobal单例管理所有的decorview,ViewRootImpl,wparams;缓存到3个对应的ArrayList,后续用同一个index取出。

WindowManagerGlobal.java

public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
。。。
ViewRootImpl root;
root = new ViewRootImpl(view.getContext(), display);//新建ViewRootImpl
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
。。。
root.setView(view, wparams, panelParentView);
...
}

ViewRootImpl是在addview里创建的。
ViewRootImpl.setView-》requestLayout()-》scheduleTraversals

 mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            doTraversal();
        }
    }
    final TraversalRunnable mTraversalRunnable = new TraversalRunnable();

doTraversal-》performTraversals-》(dispatchAttachedToWindow/performMeasure/performLayout/performDraw)

performTraversals第一次运行 会把DecorView Attache到window,由于decorView是viewgroup,会递归调用子view的dispatchAttachedToWindow
他们都使用viewgroupiml新建的View.AttachInfo
final View host = mView;
if (mFirst) {
host.dispatchAttachedToWindow(mAttachInfo, 0);
mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
            dispatchApplyInsets(host);
}
===============================================
 private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) {
        if (mView == null) {
            return;
        }
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "measure");
        try {
            mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
        } finally {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }

private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
            int desiredWindowHeight) {
        mLayoutRequested = false;
        mScrollMayChange = true;
        mInLayout = true;

        final View host = mView;
        if (host == null) {
            return;
        }
        if (DEBUG_ORIENTATION || DEBUG_LAYOUT) {
            Log.v(mTag, "Laying out " + host + " to (" +
                    host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")");
        }

        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "layout");
        try {
            host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight());
...
}

performDraw-》draw-》drawSoftware->mView.draw(canvas);
进入到view的draw过程

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