android中创建应用窗口

如前面的那篇帖子所述,每个应用窗口对应一个Activity,所以要创建应用窗口的话,首先要创建Activity。
在Context与Activity的关系那篇帖子中也讲解了Activity的创建过程,我下面就直接上源码,直接加一些
必要的注释,如果不明白的,可以自行查看源码,就不对每一句代码一一解释了。

ps:技术能力有限,难免会有错误,敬请各位指正,感谢...

大体步骤入下:
  1. 创建Activity
  2. 创建Window
  3. 向窗口中添加View
  4. 通知WindowManagerService把窗口装载到屏幕上

创建Activity

ActivityManagerService通过ApplicationThread的代理远程调用到了ApplicationThread的scheduleLaunchActivity()方法,
ApplicationThread这个类是ActivityThread的内部类。
代码入下:

这个方法做了两件事:一件事创建了一个本地的Activity的数据对象ActivityClientRecorder;一件事是通过H发送一个启动Activity的异步消息到主线程的消息队列中去。
在这里注意一下r.token,这个token是个Binder对象(ActitityRecorder),是ActivityManagerService远程传递过来的,使用这个token可以与远程的ActivityManagerService进行进程间通信。

通过H(Handler)辗转调用掉了ActivityThread的这个方法:handleLaunchActivity()

接着调用到performLaunchActivity()方法

.......
.......

通过ClassLoader创建了一个Activity实例
继续这个方法:

看下Activity的attach()方法

部分参数解释一下,token就是ActivityServiceManager传递过来的远程的ActivityRecorder,parent是需要启动的Activity的父Activity,这个是ActivityGroup里启动Activity的时候,这个就不为null了,其他情况下是null。

开始创建window了

下面是这个attach()方法的具体代码



从这里就开始创建Window的实例了:3756行
mWindow = PolicyManager.makeNewWindow(this);
mWindow.setCallback(this);
第一句是创建一个window对象,第二句是为Activity设置一个回调接口,Activity实现了Window.Callback接口

看下这个PolicyManager,
这个PolicyManager是这个包里的com.android.internal.policy,看这个PolicyManager源码可知道,真正的操作类
并不是他,而是com.android.internal.policy.impl.Policy这个,实现的是com.android.internal.policy.IPolicy这个接口,
Activity中的PolicyManager只是包装了一层com.android.internal.policy.impl.Policy而已。
下面是创建Ipolicy实例的源码,直接在加载字节码的时候已经就实例化了。

com.android.internal.policy.IPolicy总共三个方法:
看下 PolicyManager.makeNewWindow(this);这个方法:
调用了com.android.internal.policy.impl.PolicymakeNewWindow()

顺着走下去
这里直接new了一个PhoneWindow给返回了。参数中的context就是传过来的Activity
PhoneWindow的构造方法里面把context赋值给了它的mContext,创建了一个当前Activity的LayoutInflater
代码入下:
调用了下父类的构造器:
所以应用窗口的Window.getContext()就是返回的Activity的实例

到这里Window已经建立起来了,咱们再回到Activity的attach()方法:
mWindow就是PhoneWindow的实例。

3777行是为Window对象赋值WindowManager
进去看下:

window的appToken就是Activity中的mToken.
调用这个方法的时候wm传的是null,所以第一次调用的时候肯定会创建一个WindowManagerImpl的实例,是单例的,同一个
程序只有一个WindowManagerImpl实例。然后把wm包装到LocalWindowManager中,可以看出 LocalWindowManager
只是一个壳。然后把这个壳返回给Activity。
再次回到Activity的attach()方法:
3781行把这个WindowManager实例赋值给了Activity的mWindowManager

再次回到ActivityThread的performLaunchActivity()方法中
1611行调用了Activity的onCreate()方法
Instrumentation中的代码如下:
1047行调用了activity的onCreate()方法
在Activity的onCreate方法中的重载就是咱们应用程序员的事情了,咱们通常要在conCreate()方法调用setContentView()来
把布局文件或者View对象设置进去,之后界面就出现了。

开始添加View了

下面看看这个过程:
在Activity的onCreate()方法
mCalled表示代表onCreate方法是否被调用过。

我们自己的Activity的代码通常这么写:
protected void onCreate(Bundle savedInstanceState) {
         super.onCreate();
        setContentView(R.layout.main);
}

这个方法我们重写的父类的,应用程序写的代码不是由自己调用而是由Android系统调用,那么这种就是所谓的回调模式,通常
平台级的产品都是这么设计,这样设计就是给开发者一个标准的模板,相当于协议,做平台的一个程序,就一般按照平台
的这种模式去写,好处就是:对于平台来说,可控。对于开发者来说,简单。

应用开发者又调用了Activity的
setContentView()方法,有几个重载的方法,只看一个,咱们进去看看这个方法怎么执行的:
getWindow就是咱们上面创建的PhoneWindow对象。
进入 PhoneWindow 的setContentView()方法
mContentParent是一个ViewGroup,如果为空的话,会执行
installDecor();
看下这个方法:
第一次加载的时候mDecor是null,generateDecor()方法就会创建一个DecorView对象赋值给mDecor,通过new DecorView(getContext(), -1);
DecorView是个ViewGroup,是FramLayout的子类,这个DecorView就是我们看到的包括标题栏在内的整个窗口的根View


generateLayout(mDecor)方法找出mContentParent
这个地方还对标题栏的显示与否做了一些操作,所以在我们不需要系统提供的标题栏的时候为什么要在setContentView()之前就
告诉系统去掉标题栏,在setContentView()之后告诉系统去掉报错的原因。
回到 PhoneWindow 的setContentView()方法
207行,mLayoutInflater.inflate(layoutResID, mContentParent)这个方法就把应用开发者传过来的布局文件给装载到
mContentParent上了。
mContentParent是mDecor的一个子视图,在标题栏下面,mContentParent就是用来存放我们应用开发者的view的。
下面请看下view层次结构:


208行到结束,回调Activity的onContentChanged()方法,告诉activity视图内容改变了。

到这里,回到ActivityThread的performLaunchActivity()

在这里可以看出不调用Activity的concreate方法,系统是不允许的。
mActivities就是放Activity数据对象的集合,用来代表所有的Activity

再次回到ActivityThread的handleLaunchActivity()方法:




handlerResumeActivity()就是到执行到Actitiviy onResume()方法之前的一系列判断,及从onCreate()到onResume()之间的声明周期函数。

开始添加让窗口显示了


接着看这个


willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
                            a.getActivityToken());
远程调用ActivityManagerService的willActivityBeVisible()方法,把Activity里面的mToken传递过去,mToken其实是一个远程ActivityRecorder的Binder引用,这个ActivityRecorder代表服务端的Activity对象。ActivityRecorder实现了IBinder。
    上面的方法主要是检查远端是否存在这个即将启动Activity。

继续走下去
 
上面的willBeVisible 是true,
就执行到这里了
调用了Activity的makeVisible()方法

然后又调用了WindowManager的addView()方法,
调用的是Window.LocalWindowManager的addView()方法,先做一些检查,像下面的代码就是检查是否为子窗口,然后做一些数据
的处理。
‘’
接着就调用了WindowManagerImpl的addView()方法

重载的addView方法如下
先创建一个ViewRoot对象,
创建三个数组
mViews存放的是DecorView
mRoots就是和DecorView对应的ViewRoot
mParams就是对应的WindowManager.LayoutParams
每个index都对应同一个窗口。
然后调用ViewRoot的setView方法
先发出重绘请求,在绘制完之后才把窗口显示在屏幕上。

然后通过sWindowSession通知WindowManagerService可以把窗口添加到屏幕上了
这样应用的窗口就被创建成功了。其实最重要的一操作就是上面这段代码,前面的都是为这里做了一个准备而已。


解释一下sWindowSesion对象
这个对象是ViewRoot一个静态方法获得的,也就是说整个应用程序只有一个IWindowSession对象

通过ServiceManager获得IWindowMananger的Binder引用,然后获得远程可以和WindowManagerService进行通信的对象
Session对象的远程引用对象.
在WindowManagerService类里面有Session mSession对象,就是应用的这个对象,可以通过mSession与WindowManagerService进行通信。


下面是各个类之间的关系,ActivityThread没有放进去,大家知道就可以了。

 



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值