Android - Activity 与 Window 与 View 之间的关系

相关系列

  • 一篇文章看明白 Android 系统启动时都干了什么
  • 一篇文章了解相见恨晚的 Android Binder 进程间通讯机制
  • 一篇文章看明白 Android 从点击应用图标到界面显示的过程
  • 一篇文章看明白 Activity 与 Window 与 View 之间的关系
  • 一篇文章看明白 Android 图形系统 Surface 与 SurfaceFlinger 之间的关系
  • 一篇文章看明白 Android Service 启动过程
  • 一篇文章看明白 Android PackageManagerService 工作流程
  • 一篇文章看明白 Android v1 & v2 签名机制

概述

我们知道 Activity 启动后就可以看到我们写的 Layout 布局界面,Activity 从 setContentView() 到显示中间做了什么呢?下面我们就来分析下这个过程。

如不了解 Activity 的启动过程请参阅:Activity 启动过程

本文主要对于以下问题进行分析:

  • Window 是什么?
  • Activity 与 PhoneWindow 与 DecorView 之间什么关系?

onCreate() - Window 创建过程

在 Activity 创建过程中执行 scheduleLaunchActivity() 之后便调用到了 handleLaunchActivity() 方法。

ActivityThread.handleLaunchActivity():

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {handleConfigurationChanged(null, null);//初始化 WindowManagerService,主要是获取到 WindowManagerService 代理对象WindowManagerGlobal.initialize();//详情见下面分析Activity a = performLaunchActivity(r, customIntent);if (a != null) {r.createdConfig = new Configuration(mConfiguration);//详见下面分析 [onResume() - Window 显示过程]handleResumeActivity(r.token, false, r.isForward,!r.activity.mFinished && !r.startsNotResumed);...}...
}...private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {...Activity activity = null;//获取 ClassLoaderjava.lang.ClassLoader cl = r.packageInfo.getClassLoader();//创建目标 Activity 对象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);}//创建 Application 对象Application app = r.packageInfo.makeApplication(false, mInstrumentation);if (activity != null) {Context appContext = createBaseContextForActivity(r, activity);CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());Configuration config = new Configuration(mCompatConfiguration);//详情见下面分析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);...//回调 Activity.onCreate()if (r.isPersistable()) {mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);} else {mInstrumentation.callActivityOnCreate(activity, r.state);}...return activity;
}...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) {attachBaseContext(context);mWindow = new PhoneWindow(this); //创建 PhoneWindowmWindow.setCallback(this);mWindow.setOnWindowDismissedCallback(this);mWindow.getLayoutInflater().setPrivateFactory(this);...mApplication = application; //所属的 Application...//设置并获取 WindowManagerImpl 对象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();mCurrentConfig = config;
}

可看出 Activity 里新建一个 PhoneWindow 对象。在 Android 中,Window 是个抽象的概念, Android 中 Window 的具体实现类是 PhoneWindow,Activity 和 Dialog 中的 Window 对象都是 PhoneWindow。

同时得到一个 WindowManager 对象,WindowManager 是一个抽象类,这个 WindowManager 的具体实现是在 WindowManagerImpl 中,对比 Context 和 ContextImpl。

Window.setWindowManager():

public void setWindowManager(WindowManager wm, IBinder appToken, String appName, boolean hardwareAccelerated) { ...    mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);...
}

每个 Activity 会有一个 WindowManager 对象,这个 mWindowManager 就是和 WindowManagerService 进行通信,也是 WindowManagerService 识别 View 具体属于那个 Activity 的关键,创建时传入 IBinder 类型的 mToken。

mWindow.setWindowManager(..., mToken, ..., ...)

这个 Activity 的 mToken,这个 mToken 是一个 IBinder,WindowManagerService 就是通过这个 IBinder 来管理 Activity 里的 View。

回调 Activity.onCreate() 后,会执行 setContentView() 方法将我们写的 Layout 布局页面设置给 Activity。

Activity.setContentView():

public void setContentView(@LayoutRes int layoutResID) {getWindow().setContentView(layoutResID);        initWindowDecorActionBar();
}

PhoneWindow.setContentView():

public void setContentView(int layoutResID) {...    installDecor(); ...
}

PhoneWindow.installDecor():

private void installDecor() {
//根据不同的 Theme,创建不同的 DecorView,DecorView 是一个 FrameLayout
}

这时只是创建了 PhoneWindow,和DecorView,但目前二者也没有任何关系,产生关系是在ActivityThread.performResumeActivity 中,再调用 r.activity.performResume(),调用 r.activity.makeVisible,将 DecorView 添加到当前的 Window 上。

onResume() - Window 显示过程

Activity 与 PhoneWindow 与 DecorView 关系图:

ActivityThread.handleResumeActivity():

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) {//执行到 onResume()ActivityClientRecord r = performResumeActivity(token, clearHide);if (r != null) {final Activity a = r.activity;boolean willBeVisible = !a.mStartedActivity;...if (r.window == null && !a.mFinished && willBeVisible) {r.window = r.activity.getWindow();View decor = r.window.getDecorView();decor.setVisibility(View.INVISIBLE);ViewManager wm = a.getWindowManager();WindowManager.LayoutParams l = r.window.getAttributes();a.mDecor = decor;l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;l.softInputMode |= forwardBit;if (a.mVisibleFromClient) {a.mWindowAdded = true;wm.addView(decor, l);}}...if (!r.activity.mFinished && willBeVisible&& r.activity.mDecor != null && !r.hideForNow) {...mNumVisibleActivities++;if (r.activity.mVisibleFromClient) {//添加视图,详见下面分析r.activity.makeVisible(); }}//resume 完成if (reallyResume) {ActivityManagerNative.getDefault().activityResumed(token);}} else {...}
}public final ActivityClientRecord performResumeActivity(IBinder token, boolean clearHide) {ActivityClientRecord r = mActivities.get(token);if (r != null && !r.activity.mFinished) {...//回调 onResume()r.activity.performResume();...}return r;
}

Activity.makeVisible():

void makeVisible() {if (!mWindowAdded) {ViewManager wm = getWindowManager();//详见下面分析wm.addView(mDecor, getWindow().getAttributes());mWindowAdded = true;}mDecor.setVisibility(View.VISIBLE);
}

WindowManager 的 addView 的具体实现在 WindowManagerImpl 中,而 WindowManagerImpl 的 addView 又会调用 WindowManagerGlobal.addView()。

WindowManagerGlobal.addView():

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

这个过程创建一个 ViewRootImpl,并将之前创建的 DecoView 作为参数传入,以后 DecoView 的事件都由 ViewRootImpl 来管理了,比如,DecoView 上添加 View,删除 View。ViewRootImpl 实现了 ViewParent 这个接口,这个接口最常见的一个方法是 requestLayout()。

ViewRootImpl 是个 ViewParent,在 DecoView 添加的 View 时,就会将 View 中的 ViewParent 设为 DecoView 所在的 ViewRootImpl,View 的 ViewParent 相同时,理解为这些 View 在一个 View 链上。所以每当调用 View 的 requestLayout()时,其实是调用到 ViewRootImpl,ViewRootImpl 会控制整个事件的流程。可以看出一个 ViewRootImpl 对添加到 DecoView 的所有 View 进行事件管理。

ViewRootImpl:

public ViewRootImpl(Context context, Display display) {mContext = context;//获取 IWindowSession 的代理类mWindowSession = WindowManagerGlobal.getWindowSession();mDisplay = display;mThread = Thread.currentThread(); //主线程mWindow = new W(this); mChoreographer = Choreographer.getInstance();...
}public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {synchronized (this) {...//通过 Binder 调用,进入 system 进程的 Sessionres = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,getHostVisibility(), mDisplay.getDisplayId(),mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,mAttachInfo.mOutsets, mInputChannel);...}
}

WindowManagerGlobal:

public static IWindowSession getWindowSession() {synchronized (WindowManagerGlobal.class) {if (sWindowSession == null) {try {//获取 InputManagerService 的代理类InputMethodManager imm = InputMethodManager.getInstance();//获取 WindowManagerService 的代理类IWindowManager windowManager = getWindowManagerService();//经过 Binder 调用,最终调用 WindowManagerServicesWindowSession = windowManager.openSession(new IWindowSessionCallback.Stub() {...},imm.getClient(), imm.getInputContext());} catch (RemoteException e) {...}}return sWindowSession}
}

通过 binder 调用进入 system_server 进程。
Session:

final class Session extends IWindowSession.Stub implements IBinder.DeathRecipient {public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) {//详情见下面return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,outContentInsets, outStableInsets, outOutsets, outInputChannel);}
}

WindowManagerService:

public int addWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) {...WindowToken token = mTokenMap.get(attrs.token);//创建 WindowStateWindowState win = new WindowState(this, session, client, token,attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);...//调整 WindowManager 的 LayoutParams 参数mPolicy.adjustWindowParamsLw(win.mAttrs);res = mPolicy.prepareAddWindowLw(win, attrs);addWindowToListInOrderLocked(win, true);// 设置 inputmInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);// 创建 Surface 与 SurfaceFlinger 通信,详见下面[SurfaceFlinger 图形系统]win.attach();mWindowMap.put(client.asBinder(), win);if (win.canReceiveKeys()) {//当该窗口能接收按键事件,则更新聚焦窗口focusChanged = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_ASSIGN_LAYERS,false /*updateInputWindows*/);}assignLayersLocked(displayContent.getWindowList());...
}

创建 Surface 的过程详见:SurfaceFlinger 图形系统

Activity 中 Window 创建过程:

总结

  • Window 是什么?

Window 是 Android 中窗口的宏观定义,主要是管理 View 的创建,以及与 ViewRootImpl 的交互,将 Activity 与 View 解耦。

  • Activity 与 PhoneWindow 与 DecorView 之间什么关系?

一个 Activity 对应一个 Window 也就是 PhoneWindow,一个 PhoneWindow 持有一个 DecorView 的实例,DecorView 本身是一个 FrameLayout。

参考资料

  • 以Window视角来看startActivity
  • Android视图框架Activity,Window,View,ViewRootImpl理解
  • 《深入理解 Android 内核设计思想》

其他系列

  • Android 屏幕适配全攻略
  • Windows 环境下载 Android 源码
  • Android 性能优化-UI优化
  • Android 性能优化-内存优化
  • Java 虚拟机内存分配机制
  • Java 虚拟机垃圾回收机制
  • 一篇文章看明白 TCP/IP,TCP,UDP,IP,Socket 之间的关系
  • 一篇文章看明白 HTTP,HTTPS,SSL/TSL 之间的关系

Gradle 系列

  • Gradle - 简介
  • Gradle - Groovy Language
  • Gradle - DSL
  • Gradle - Android Plugin DSL
  • Gradle - 插件开发
  • Gradle - 插件发布

更多文章:

这是我博客长期更新的项目,欢迎大家 Star。
https://github.com/jeanboydev/Android-ReadTheFuckingSourceCode

我的公众号

欢迎你「扫一扫」下面的二维码,关注我的公众号,可以接受最新的文章推送,有丰厚的抽奖活动和福利等着你哦!?

如果你有什么疑问或者问题,可以 点击这里 提交 issue,也可以发邮件给我 jeanboy@foxmail.com。

同时欢迎你 来一起交流学习,群里有很多大牛和学习资料,相信一定能帮助到你!

一篇文章看明白 Activity 与 Window 与 View 之间的关系相关推荐

  1. 一篇文章看明白 Android 图形系统 Surface 与 SurfaceFlinger 之间的关系

    Android - SurfaceFlinger 图形系统 相关系列 一篇文章看明白 Android 系统启动时都干了什么 一篇文章了解相见恨晚的 Android Binder 进程间通讯机制 一篇文 ...

  2. android 如何获得activity的view对象,Android的Activity 、 Window 、 View之间的关系

    什么是Activity .View . Window? Activity:是Android 四大组件之一, 是存放View对象的容器,也是我们界面的载体,可以用来展示一个界面.它有一个SetConte ...

  3. 一篇文章看明白 Android PackageManagerService 工作流程

    Android - PackageMangerService 分析 相关系列 一篇文章看明白 Android 系统启动时都干了什么 一篇文章了解相见恨晚的 Android Binder 进程间通讯机制 ...

  4. 一篇文章看明白 Android v1 v2 签名机制

    Android - v1 & v2 签名机制 相关系列 一篇文章看明白 Android 系统启动时都干了什么 一篇文章了解相见恨晚的 Android Binder 进程间通讯机制 一篇文章看明 ...

  5. 一篇文章看明白 Android Service 启动过程

    Android - Service 启动过程 相关系列 一篇文章看明白 Android 系统启动时都干了什么 一篇文章了解相见恨晚的 Android Binder 进程间通讯机制 一篇文章看明白 An ...

  6. 转载:一篇文章看明白 Android 系统启动时都干了什么

    最近在看<深入理解Android内核设计思想>,老实说,作为教材,这本书实在写的不好.本来内核的东西就比应用层繁杂,需要有个条绳子牵着,有个框子框着才不好跟丢.这个书老是在章节开头抛出一些 ...

  7. 文化袁探索专栏——Activity、Window和View三者间关系

    文化袁探索专栏--Activity.Window和View三者间关系 <文化袁探索专栏--View三大流程#Measure 文化袁探索专栏--View三大流程#Layout 文化袁探索专栏--H ...

  8. 一篇文章看明白 HashMap 工作原理

    HashMap 源码分析 简介 HashMap 是 Java 语言中常用的用于存放键值对数据类型的集合类.随着 JDK(Java Developmet Kit)版本的更新,JDK 1.8 对 Hash ...

  9. 一篇文章看明白什么是DV、OV、EV证书

    目录 一.序言 二.DV/OV/EV证书说明 三.DV/OV/EV证书区别 WIN系统 OV型和EV型证书在浏览器显示效果 WIN系统 DV证书显示效果​ MAC Firefox火狐浏览器DV证书显示 ...

  10. android类之间的关系,Android 中Activity,Window和View之间的关系

    Activity是Android应用程序的载体,允许用户在其上创建一个用户界面,并提供用户处理事件的API,如 onKeyEvent, onTouchEvent等. 并维护应用程序的生命周期.Acti ...

最新文章

  1. 简单总结nodejs处理tcp连接的核心流程
  2. 知识驱动的推荐系统:现状与展望
  3. ExpandableListView的使用以及信息的高亮显示
  4. 浅谈Android事件分发机制
  5. 一、 Python概述、变量
  6. Spring MVC URL的映射问题 ;Spring MVC 跳转与iframe包含地址问题
  7. 一号教学楼供配电设计
  8. 信息技术开拓视野——记IT战略规划与企业架构培训课程
  9. 深度学习和神经网络介绍
  10. 获取U盘 VID,PID
  11. 985硕毕业,面试13家企业,拿7个大厂offer,回顾面试总结
  12. django 基础框架学习 (三)
  13. 23行代码下载逆水寒壁纸图片
  14. 凝思系统机器名怎么查看_凝思操作系统Custom Linx安装教程
  15. access 有效性规则和有效性文本
  16. 期货怎么克服频繁止损(期货交易怎么止损)
  17. 字符串转时间(time_t)
  18. 大咖说·图书分享|了不起的JavaScript工程师:从前端到全端高级进阶
  19. Cisco交换机端口假死(err-disable)解决方法
  20. leetcode之股票问题

热门文章

  1. 计算机的网线连接路由器的什么接口,tp-link路由器网线插哪个口 tplink路由器网线连接图解...
  2. 【计及DG和相关性的纯交流三点估计随机潮流计算方法】
  3. 支付宝客户端拉起支付
  4. python显示invalid character_python提示invalid character in identifier
  5. 关闭jupyter notebook报错:python.exe-应用程序错误
  6. SP商BI平台(MP子平台)——通信增值业务运营SP公司
  7. CTS、CLS和CLR
  8. 寒霜朋克计算机丢失,寒霜朋克无法进入游戏解决方法 寒霜朋克无法进入游戏怎么办...
  9. Hulu热招|广告智能团队
  10. 连接MyBatis内部SqlSession与业务接口的代理类MapperProxy