Android Activity从0~1显示界面的过程 基于Android11源码分析

Android Activity显示界面的过程 基于Android11源码分析

从Activity的创建开始,因为要显示界面 需要window,window的创建是在Activity创建的时候创建的。

我们知道,当我们启动一个Activity时,AMS会通过Binder的方式通知Activtiy所在的进程,并通过H类切换线程到主线程执行,会调用handleLaunchActivity,然后调用performLaunchActivity。

Activity中window的创建 attach

ActivityThread.java

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    /../
	//为Activity创建context
    ContextImpl appContext = createBaseContextForActivity(r);
    Activity activity = null;
    try {
        //使用Instrumentation通过反射创建Activity 之所以使用反射是为了解耦
        java.lang.ClassLoader cl = appContext.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        /../
    } catch (Exception e) {
        /../
    }

    try {
        //获取应用进程的Application对象 没有的话就创建一个
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);

        /../

        if (activity != null) {
           /../
            Window window = null;
            //这里 window 赋值不赋值 都可以 因为这个window是在创建PhoneWindow的时候使用的,有这个window的话 会复用它的decorView 和一些其他参数 ,具体可以看PhoneWindow的构造函数源码
            if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                    window = r.mPendingRemoveWindow;
                    r.mPendingRemoveWindow = null;
                    r.mPendingRemoveWindowManager = null;
                }
            /../
            //完成最后ActivityContext的创建,传入Activity对象。因为context会持有Activity对象,所以当我们需要使用context的时候尽可能使用applicationContext对象,防止内存泄漏
            appContext.setOuterContext(activity);
            //调用attach
            activity.attach(appContext, this, getInstrumentation(), r.token,
                    r.ident, app, r.intent, r.activityInfo, title, r.parent,
                    r.embeddedID, r.lastNonConfigurationInstances, config,
                    r.referrer, r.voiceInteractor, window, r.configCallback,
                    r.assistToken, r.shareableActivityToken);

           /../
             //回调Activity的onCreate方法
            if (r.isPersistable()) {
                mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
            } else {
                mInstrumentation.callActivityOnCreate(activity, r.state);
            }
           /../
        }
        /../

    } catch (SuperNotCalledException e) {
        throw e;

    } catch (Exception e) {
        /../
    }

    return activity;
}

Activity.java

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, IBinder assistToken,
        IBinder shareableActivityToken) {
    //调用Activity的attachBaseContext方法 我们可以重写这个方法,这个方法在onCreate之前执行
    attachBaseContext(context);

    /../
	//创建window PhoneWindow 是 Window的具体实现类 注意我们虽然在这里给Activity创建了Window,但还没有添加window到WMS中!!!
    mWindow = new PhoneWindow(this, window, activityConfigCallback);
    mWindow.setWindowControllerCallback(mWindowControllerCallback);
    //设置Window的Callback 为 Activity对象本身 因为Activity实现了Window.Callback接口
    mWindow.setCallback(this);
    mWindow.setOnWindowDismissedCallback(this);
    mWindow.getLayoutInflater().setPrivateFactory(this);
    if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
        mWindow.setSoftInputMode(info.softInputMode);
    }
    if (info.uiOptions != 0) {
        mWindow.setUiOptions(info.uiOptions);
    }
    /../ //初始化了一些Activity中的成员变量, 具体可以看源码 为了简洁 就省略掉了
    //设置window的WindowManager
    mWindow.setWindowManager(
            (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
            mToken, mComponent.flattenToString(),
            (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
    if (mParent != null) {
        mWindow.setContainer(mParent.getWindow());
    }
    mWindowManager = mWindow.getWindowManager();
    /../
}

Activity中window中的decorView的创建 onCreate

然后 回到performLaunchActivity方法中回调 Activity的onCreate方法

Activity.java

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //在这里 会去调用Activity的父类AppCompatActivity的setContentView方法
        setContentView(R.layout.activity_main)
   }

AppCompatActivity.java

继承自FragmentActivity -继承自-> androidx.activity.ComponentActivity --> androidx.core.app.ComponentActivity --> Activity

Activity实现了Window.Callback 接口

public void setContentView(@LayoutRes int layoutResID) {
    //在设置内容视图前,初始化各种ViewTree的所有者(ViewTreeLifecycleOwner、ViewTreeViewModelStoreOwner、ViewTreeSavedStateRegistryOwner)
    initViewTreeOwners();
    //获取委托AppCompatDelegate类的对象 调用它的setContentView方法。
    //AppCompatDelegate是一个抽象类,具体实现类是AppCompatDelegateImpl
    getDelegate().setContentView(layoutResID);
}

AppCompatDelegateImpl.java

public void setContentView(int resId) {
    //给Window添加DecorView
    ensureSubDecor();
    //获取DecorView中的id为content FrameLayout,即内容视图
    //window中包含DecorView,DecorView是一个LinearLayout,它的内部有titleView 和 		//contentView 两个子View, 都是FrameLayout布局
    ViewGroup contentParent = mSubDecor.findViewById(android.R.id.content);
    //清空contentView中的所有子View 
    contentParent.removeAllViews();
    //使用LayoutInflater解析xml布局,生成对应的ViewTree,并把加载出来的view放到DecorView的contentView中
    LayoutInflater.from(mContext).inflate(resId, contentParent);
    //调用WindowCallback的onContentChanged方法,通知WindowcontentView的内容发生了改变
    //Activity实现了Window.Callback函数,但是onContentChanged方法为空实现,所以目的是当Activity的布局改动时,即setContentView()或者addContentView()方法执行完毕时就会调用该方法。我们可以通过该回调 了解到contentView 已经发生了改变(注意当此方法回调时是已经完成了改变了) 
    mAppCompatWindowCallback.getWrapped().onContentChanged();
}

 private void ensureSubDecor() {
     //还未安装DecorView中的默认布局时
        if (!mSubDecorInstalled) {
            //根据Activity的theme 创建DecorView中的默认布局(titleView和ContentView) createSubDecor 最后会调用window的setContentView
            mSubDecor = createSubDecor();

            /../

            mSubDecorInstalled = true;

            /../
        }
    }

PhoneWindow.java

public void setContentView(View view, ViewGroup.LayoutParams params) {
    if (mContentParent == null) {
        //未安装decorView的话 创建decorView
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }

    /../
        //将传递过来的View添加到DecorView中的contentView中
        mContentParent.addView(view, params);
    /../
}

private void installDecor() {
        mForceDecorInstall = false;
        if (mDecor == null) {
            //生成DecorView并返回decorView
            mDecor = generateDecor(-1);
           /../
        } else {
            //设置decorview的window
            mDecor.setWindow(this);
        }
        if (mContentParent == null) {
            //初始化decorView布局,配置参数(背景等),返回decorView中android.R.id.content所对应的View
            mContentParent = generateLayout(mDecor);

            /../
        }
    }

到了此时,我们Activity中window已经创建好了,同时window中的decorView也已经创建完毕,也把我们自己的布局放入到decorView的ContentView中了。但是这个时候view还没有显示出来!!!因为我们还没有添加window到WMS中,也没有执行View的绘制流程。目前只是创建好了ViewTree的结构。

Activity 添加window到WMS中 并显示 onResume

目前Activity只是执行了onCreate方法,当执行onResume方法时就开始执行View的显示流程了。所以我们要回到ActivityThread中,AMS会通过Binder,调用handleResumeActivity方法。(注意AMS通过Binder调用ApplicationThread的方法,此时是在BInder线程池中运行的,所以会通过mH(这是一个Handler)切换到主线程执行handleResumeActivity,具体看源码)

ActivityThread.java

public void handleResumeActivity(ActivityClientRecord r, boolean finalStateRequest,
        boolean isForward, String reason) {
    /../
        //执行Activity的onResume方法,所以onResume会先执行,然后再添加window,开始绘制流程
    if (!performResumeActivity(r, finalStateRequest, reason)) {
            return;
    }    
    /../
    
    if (r.window == null && !a.mFinished && willBeVisible) {
        r.window = r.activity.getWindow();
        View decor = r.window.getDecorView();
        //让decorView可见
        decor.setVisibility(View.INVISIBLE);
        //获取WindowManager
        ViewManager wm = a.getWindowManager();
        WindowManager.LayoutParams l = r.window.getAttributes();
        /../
        //WindowManager是接口,具体实现是WindowManagerImpl,WindowManagerImpl又把功能委托给WindowManagerGlobal来实现
        wm.addView(decor, l);
        /../
    }
}

WindowManagerGlobal

ublic void addView(View view, ViewGroup.LayoutParams params,
        Display display, Window parentWindow, int userId) {
  /../

    ViewRootImpl root;
/../
		//创建view对应的ViewRootImpl ViewRootImpl用于和WMS进行通信,控制View的三大绘制流程
        root = new ViewRootImpl(view.getContext(), display);

        view.setLayoutParams(wparams);
		//把该view相应参数添加到相应的数组中
        mViews.add(view);
        mRoots.add(root);
        mParams.add(wparams);
    
        try {
            //进入到ViewRootImpl中执行setView方法
            root.setView(view, wparams, panelParentView, userId);
        } catch (RuntimeException e) {
           /../
        }
    }
}

ViewRootImpl.java

viewRootImp中的surface是通过relayoutWindow()方法调用WMS的relayout()方法,来进行的实际初始化工作。WMS会负责创建Surface并与Window进行绑定。一般情况下一个Winodw对应一个Surface。我们onDraw方法中的canvas参数就是通过surface获取的。那么surface是如何显示到屏幕上的呢?是SurfaceFlinger中抽象了一个layer的概念,每个Surface对应一个layer,surfaceFlinger会负责把layer进行图像混合,然后通过OpenGL ES输出到framebuffer中,供显示屏刷新时显示。

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
        int userId) {
    synchronized (this) {
        /../
        //看到了我们常用的刷新布局的方法
        requestLayout();
        /../
        //通过Session和WMS进行通信,WMS会创建window,结合参数计算window宽高,最后使用ViewRootImpl开启DecorView的测量布局绘制,addToDisplayAsUser会调用wms的addWindow方法。
        res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(), userId,
                            mInsetsController.getRequestedVisibility(), inputChannel, mTempInsets,
                            mTempControls);
        
    }
}

public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            checkThread(); //检查是否在主线程执行
            mLayoutRequested = true;
            scheduleTraversals(); //继续跟
        }
    }

void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            //加入同步屏障 让messageQueue中的同步事件都不能再执行,只能执行异步事件,为了保证Vsync信号到来时可以第一时间执行 三大绘制流程 防止卡顿
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null); //我们向Choreographer mChoreographer提交了一个Runnable Choreographer是编舞者,负责从显示系统接收脉冲信号(Vsync),编排渲染下一帧的绘制工作,负责获取Vsync同步信号并控制UI线程完成图像绘制的类。
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }
//这里面只有一个方法就是 执行doTraversal();
final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            //会移除同步屏障并开始自顶向下的执行View树的三大绘制流程
            doTraversal();
        }
    }

WindowManagerService.java

public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility,
        int displayId, int requestUserId, InsetsState requestedVisibility,
        InputChannel outInputChannel, InsetsState outInsetsState,
        InsetsSourceControl[] outActiveControls) {
    /../
    //权限检查
    int res = mPolicy.checkAddPermission(attrs.type, isRoundedCornerOverlay, attrs.packageName,
            appOp);
    if (res != ADD_OKAY) {
        return res;
    }

    WindowState parentWindow = null;
  	/../

    synchronized (mGlobalLock) {
       /../
		//确定窗口想要添加到哪个DisplayContent中, DisplayContent对应一个屏幕
        final DisplayContent displayContent = getDisplayContentOrCreate(displayId, attrs.token);

       	/../
      	//判断窗口的层级
        /../
        // 获取Windowtoken 如果获取的为null  会创建token
        WindowToken token = displayContent.getWindowToken(
                hasParent ? parentWindow.mAttrs.token : attrs.token);
        /../
		//创建windowstate
        final WindowState win = new WindowState(this, session, client, token, parentWindow,appOp[0], attrs, viewVisibility, session.mUid, userId,session.mCanAddInternalSystemWindow);
        /../
        // 添加windowstate 和 binder 关联
        mWindowMap.put(client.asBinder(), win);
        /../
        // windowstate和token关联
        win.mToken.addWindow(win);
        /../
    return res;
}

Choreographer.java

public void postCallback(int callbackType, Runnable action, Object token) {
    postCallbackDelayed(callbackType, action, token, 0);
}
private void postCallbackDelayedInternal(int callbackType, Object action, Object token, long delayMillis) {
    synchronized (mLock) {
        final long now = SystemClock.uptimeMillis();
        final long dueTime = now + delayMillis;
        // 加入mCallbackQueues
        mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
		
		// 这里的delayMills为0,所以会走到scheduleFrameLocked()
        if (dueTime <= now) { 
            scheduleFrameLocked(now);
        }
        ...
    }
}
private void scheduleFrameLocked(long now) {
    if (!mFrameScheduled) {
        mFrameScheduled = true;
        ...
        // 判断当前thread是否运行loop
        if (isRunningOnLooperThreadLocked()) {
            scheduleVsyncLocked();
        }
   }
}
private void scheduleVsyncLocked() {
    // 注册订阅了vsync信号
    mDisplayEventReceiver.scheduleVsync();
}
// DisplayEventReceiver
public void scheduleVsync() {
    ...
    // 注册订阅了vsync信号
    nativeScheduleVsync(mReceiverPtr);
}
//什么时候会收到Vsync信号呢?Choreographer内部类DisplayEventReceiver的onVsync方法、

Choreographer内部类DisplayEventReceiver

public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
	mTimestampNanos = timestampNanos;
    mFrame = frame;
    Message msg = Message.obtain(mHandler, this);
    // 设置成异步消息 防止被同步屏障 屏蔽
    msg.setAsynchronous(true);
    mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS);
}
//当handler执行刚刚发送的消息时,调用run方法
public void run() {
    mHavePendingVsync = false;
    doFrame(mTimestampNanos, mFrame);
}
void doFrame(long frameTimeNanos, int frame) {
	...
	doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
}
void doCallbacks(int callbackType, long frameTimeNanos) {
    CallbackRecord callbacks;
    // 从mCallbackQueues取出
    callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(
                    now / TimeUtils.NANOS_PER_MS);
    for (CallbackRecord c = callbacks; c != null; c = c.next) {
         c.run(frameTimeNanos);
    }
}
// CallbackRecord
public void run(long frameTimeNanos) {
    if (token == FRAME_CALLBACK_TOKEN) {
        ((FrameCallback)action).doFrame(frameTimeNanos);
    } else {
        // 这里也即是调用了TraservalRunnable的run方法,也即是三个绘制流程,开始执行doTraversal(), 取消同步屏障,通过performTraversal方法开始依次调用performMeasure、performLayout、performDraw方法
        ((Runnable)action).run();
    }
}    

当Vsync信号到来时,就开始执行三大绘制流程,把View绘制在surface上,完成后surfaceFlinger会混合这一段Vsync信号间隔时间的所有的surface,然后输出到framebuffer中,等待下一个Vsync信号到来时,进行帧替换。

详细可以了解 黄油计划、SurfaceFlinger

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值