Activity的Window创建

Activity的启动最终会由ActivityThread中的perforLaunchActivity()来完成整个启动过程,在这个方法内部会通过类加载器创建Activity的实例对象,并调用其attach方法为其关联运行过程中所依赖的一系列上下文环境变量。

在attach方法里,系统会创建Activity所属的Window对象(new了一个PhoneWindow)并为其设置回调接口。由于Activity实现了Window的Callback接口,因此当Window接收到外界的状态改变时就会回调Activity的方法。比如onAttachToWindow、onDetachedFromWindow、dispatchTouchEvent等等(触摸事件的传递)。

setContentView其实是调用了Window的setContentView方法,即PhoneWindow的setContentView方法。

简单说就是在:

1.ActivityThread的attach方法中为Activity new了一个PhoneWindow(通过PolicyManager创建的,真正实现类是Policy类)

2.然后PhoneWindow为Activity new了一个顶级View即DecorView(它是一个FrameLayout),它包含标题栏跟内容栏。内容栏是一定要存在的,并且内容栏有固定的id就是android.R.id.content。

3.再然后将Activity的视图添加到DecorView中的mContentParent中,此时会回调Activity的onContentChanged方法。这个时候DecorView已经被创建并初始化完毕。这时的Window还没有通过WindowManager正式添加到WindowManagerService中,还不能提供具体的功能,无法接收外界的输入信息。

4. 最后在ActivityThread的handleResumeActivity方法中,首先调用Activity的onResume方法,接着会调用Activity的makeVisible方法。在makeVisible方法中,通过WindowManager的addView方法将创建好的DecorView添加到WindowManagerService中。此时Activity的视图才能被用户看到。

Dialog视图的添加也是类似,普通的Dialog有一个特殊之处,那就是必须采用Activity的Context,如果采用Application的Context,那么就会报错。会报没有token所导致,而应用token一般只有Activity拥有,所以需要用Activity作为Context来现实对话框。

另外,系统Window比较特殊,它可以不需要token,因此也可以指定对话框的Window类型为系统类型就可以正常弹出对话框。通过WindowManager.LayoutParams的type参数指定Window的层级。例如指定为LayoutParams.TYPE_SYSTEM-OVERLAY,不过使用系统Window类型需要在AndroidManifest中声明权限。

Toast和Dialog不同,它的工作过程稍微复杂。首先Toast也是基于Window来实现的。但是由于Toast具有定时取消这一功能,所以系统采用了Handler.

在Toast的内部有两类IPC过程,第一类是Toast访问NotificationManagerService,第二类是NotificationManagerService回调Toast里的TN接口。

TN是一个Binder类,当NMS处理Toast的现实或者隐藏请求的时候会跨进程回调TN中的方法,这个时候由于TN运行在Binder线程池中,所以需要通过Handler将其切换到当前线程中。这里的当前线程是指发送Toast请求所在的线程。由于这里使用了Handler,所以这意味着Toast无法在没有Looper的线程中弹出,这是因为Handler需要使用Looper才能完成切换线程的功能。

你可能感兴趣的:(Activity的Window创建)