您的位置:首页 > 移动开发 > Android开发

android窗体加载过程剖析之消息处理的注册机制

2012-09-17 10:18 471 查看
这一篇是接着上一篇android窗体加载过程剖析之一Activity的初始化

的内容继续往下走。 在查阅了网上很多文章和源码之后,终于对android这一块的内容有了一定的了解。网上相似内容的文章似乎已经有蛮多篇了,不过我想在写文章的同时也可以进一步加深自己的理解,所以就再自行梳理了一遍这块内容。

由上一篇文章我们知道,Window类中存放的WindowManager实际上是一个WindowManagerImpl对象(LocalWindowManager相当于一个包装器):

源码路径:frameworks\base\core\java\android\view\Window.java

源码中国链接:http://www.oschina.net/code/explore/android-2.2-froyo/android/view/Window.java

public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;
mAppName = appName;
if (wm == null) {
wm = WindowManagerImpl.getDefault();
}
mWindowManager = new LocalWindowManager(wm, hardwareAccelerated);
}
那么接下来就看看WindowManagerImpl的代码:

源码路径:frameworks\base\core\java\android\view\WindowManagerImpl.java

源码中国链接:http://www.oschina.net/code/explore/android-2.2-froyo/android/view/WindowManagerImpl.java

private void addView(View view, ViewGroup.LayoutParams params,
CompatibilityInfoHolder cih, boolean nest) {
if (false) Log.v("WindowManager", "addView view=" + view);

if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException(
"Params must be WindowManager.LayoutParams");
}

final WindowManager.LayoutParams wparams
= (WindowManager.LayoutParams)params;

ViewRootImpl root;
View panelParentView = null;

synchronized (this) {
...

root = new ViewRootImpl(view.getContext());
root.mAddNesting = 1;
if (cih == null) {
root.mCompatibilityInfo = new CompatibilityInfoHolder();
} else {
root.mCompatibilityInfo = cih;
}

view.setLayoutParams(wparams);

if (mViews == null) {
index = 1;
mViews = new View[1];
mRoots = new ViewRootImpl[1];
mParams = new WindowManager.LayoutParams[1];
} else {
index = mViews.length + 1;
Object[] old = mViews;
mViews = new View[index];
System.arraycopy(old, 0, mViews, 0, index-1);
old = mRoots;
mRoots = new ViewRootImpl[index];
System.arraycopy(old, 0, mRoots, 0, index-1);
old = mParams;
mParams = new WindowManager.LayoutParams[index];
System.arraycopy(old, 0, mParams, 0, index-1);
}
index--;

mViews[index] = view;
mRoots[index] = root;
mParams[index] = wparams;
}
// do this last because it fires off messages to start doing things
root.setView(view, wparams, panelParentView);
}
我们就从第一次启动Activity添加窗体的情况来说明,由于函数有点长,因此省略掉了这种情况下不会进入的代码。

int index = findViewLocked(view, false);

findViewLocked的内容:

private int findViewLocked(View view, boolean required) {
synchronized (this) {
final int count = mViews != null ? mViews.length : 0;
for (int i=0; i<count; i++) {
if (mViews[i] == view) {
return i;
}
}
if (required) {
throw new IllegalArgumentException(
"View not attached to window manager");
}
return -1;
}
}
是在当前的窗体栈中寻找指定的View,有的话就返回在数组中的索引。由于假定的是第一次加载,那么就是返回-1.

root = new ViewRootImpl(view.getContext());
root.mAddNesting = 1;
接下来可以看到root被初始化,由于我的源码是4.0版本的,因此实例化的对象是ViewRootImpl,4,0以下是ViewRoot对象。等下再来分析下ViewRootImpl这个类,先继续往下走。

if (mViews == null) {
index = 1;
mViews = new View[1];
mRoots = new ViewRootImpl[1];
mParams = new WindowManager.LayoutParams[1];
}
新启动的窗体的根View和ViewRootImpl都被添加到了类的成员变量中,WindowManagerImpl会负责维护这些窗体,并控制事件的分发。

root.setView(view, wparams, panelParentView);
函数的最后,调用了ViewRootImpl.setView函数。

源码路径:frameworks\base\core\java\android\view\ViewRootImpl.java

源码中国链接:http://www.oschina.net/code/explore/android-2.2-froyo/android/view/ViewRoot.java

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
mFallbackEventHandler.setView(view);
mWindowAttributes.copyFrom(attrs);
attrs = mWindowAttributes;
...
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue(mInputChannel);
mInputQueueCallback.onInputQueueCreated(mInputQueue);
} else {
InputQueue.registerInputChannel(mInputChannel, mInputHandler,
Looper.myQueue());
}
}
...
}
只贴我关心的而且又是看懂了的部分,嘿嘿。

这里将传入的窗体的根view存入了类变量mView中。并且在InputQueue中注册了消息接收通道以及接收消息并处理的对象。当有按键,滚动等事件发生时,就是通过这个渠道从底层通知到了Java层。

InputQueue

源码地址 http://www.oschina.net/code/explore/android-4.0.1/core/java/android/view/InputQueue.java
An input queue provides a mechanism for an application to receive incoming input events. Currently only usable from native code.

一个给应用提供了某种机制来接收输入事件的输入队列。这个类我只看了下,没有深究,里面有一些Native的函数,这个类相当于是一个桥梁供Java层调用Native层的方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐