Android应用程序窗口设计框架二
来源:互联网 发布:wildcard ssl nginx 编辑:程序博客网 时间:2024/05/18 00:12
handleResumeActivity
performLaunchActivity函数完成了两件事:
1) Activity窗口对象的创建,通过attach函数来完成;
2) Activity视图对象的创建,通过setContentView函数来完成;
这些准备工作完成后,就可以显示该Activity了,应用程序进程通过调用handleResumeActivity函数来启动Activity的显示过程。
frameworks\base\core\java\android\app\ ActivityThread.java
final
void
handleResumeActivity(IBinder token,
boolean
clearHide,
boolean
isForward) {
unscheduleGcIdler();
ActivityClientRecord r;
try
{
①r = performResumeActivity(token, clearHide);
}
catch
(Exception e) {
...
}
if
(r !=
null
) {
final
Activity a = r.activity;
...
if
(r.window ==
null
&& !a.mFinished && willBeVisible) {
//获得为当前Activity创建的窗口PhoneWindow对象
r.window = r.activity.getWindow();
//获取为窗口创建的视图DecorView对象
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
//在attach函数中就为当前Activity创建了WindowManager对象
ViewManager wm = a.getWindowManager();
//得到该视图对象的布局参数
②WindowManager.LayoutParams l = r.window.getAttributes();
//将视图对象保存到Activity的成员变量mDecor中
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
if
(r.intent.hasCategory(Intent.CATEGORY_HOME)) {
l.idleScreenAvailable =
true
;
}
else
{
l.idleScreenAvailable =
false
;
}
l.softInputMode |= forwardBit;
if
(a.mVisibleFromClient) {
a.mWindowAdded =
true
;
//将创建的视图对象DecorView添加到Activity的窗口管理器中
③wm.addView(decor, l);
}
}
else
if
(!willBeVisible) {
...
}
...
if
(!r.onlyLocalRequest) {
r.nextIdle = mNewActivities;
mNewActivities = r;
Looper.myQueue().addIdleHandler(
new
Idler());
}
...
}
else
{
...
}
}
我们知道,在前面的performLaunchActivity函数中完成Activity的创建后,会将当前当前创建的Activity在应用程序进程端的描述符ActivityClientRecord以键值对的形式保存到ActivityThread的成员变量mActivities中:mActivities.put(r.token, r),r.token就是Activity的身份证,即是IApplicationToken.Proxy代理对象,也用于与AMS通信。上面的函数首先通过performResumeActivity从mActivities变量中取出Activity的应用程序端描述符ActivityClientRecord,然后取出前面为Activity创建的视图对象DecorView和窗口管理器WindowManager,最后将视图对象添加到窗口管理器中。
我们知道Activity引用的其实是轻量级的窗口管理器LocalWindowManager
frameworks\base\core\java\android\view\ Window.java
public
final
void
addView(View view, ViewGroup.LayoutParams params) {
WindowManager.LayoutParams wp = (WindowManager.LayoutParams)params;
CharSequence curTitle = wp.getTitle();
//应用程序窗口
if
(wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
if
(wp.token ==
null
) {
View decor = peekDecorView();
if
(decor !=
null
) {
// LayoutParams 的token设置为W本地Binder对象
wp.token = decor.getWindowToken();
}
}
if
(curTitle ==
null
|| curTitle.length() ==
0
) {
//根据窗口类型设置不同的标题
…
if
(mAppName !=
null
) {
title +=
":"
+ mAppName;
}
wp.setTitle(title);
}
}
else
{
//系统窗口
if
(wp.token ==
null
) {
wp.token = mContainer ==
null
? mAppToken : mContainer.mAppToken;
}
if
((curTitle ==
null
|| curTitle.length() ==
0
)
&& mAppName !=
null
) {
wp.setTitle(mAppName);
}
}
if
(wp.packageName ==
null
) {
wp.packageName = mContext.getPackageName();
}
if
(mHardwareAccelerated) {
wp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
}
super
.addView(view, params);
}
LocalWindowManager的addView函数对不同类型窗口的布局参数进行相应的设置,比如布局参数中的token设置,如果是应用程序窗口,则设置token为W本地Binder对象。如果不是应用程序窗口,同时当前窗口没有父窗口,则设置token为当前窗口的IApplicationToken.Proxy代理对象,否则设置为父窗口的IApplicationToken.Proxy代理对象。最后视图组件的添加工作交给其父类来完成。LocalWindowManager继承于CompatModeWrapper,是WindowManagerImpl的内部类。
frameworks\base\core\java\android\view\WindowManagerImpl.java
public
void
addView(View view, android.view.ViewGroup.LayoutParams params) {
mWindowManager.addView(view, params, mCompatibilityInfo);
}
前面我们介绍了,每一个Activity拥有一个轻量级窗口管理器,通过轻量级窗口管理器LocalWindowManager来访问重量级窗口管理器WindowManagerImpl,因此视图组件的添加过程又转交给了WindowManagerImpl来实现。
public
void
addView(View view, ViewGroup.LayoutParams params, CompatibilityInfoHolder cih) {
addView(view, params, cih,
false
);
}
该函数又调用WindowManagerImpl的另一个重载函数来添加视图组件
private
void
addView(View view, ViewGroup.LayoutParams params,
CompatibilityInfoHolder cih,
boolean
nest) {
...
final
WindowManager.LayoutParams wparams= (WindowManager.LayoutParams)params;
ViewRootImpl root;
View panelParentView =
null
;
synchronized
(
this
) {
...
//从mViews中查找当前添加的View
int
index = findViewLocked(view,
false
);
//如果已经存在,直接返回
if
(index >=
0
) {
...
return
;
}
//尚未添加当前View
if
(wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
final
int
count = mViews !=
null
? mViews.length :
0
;
for
(
int
i=
0
; i<count; i++)=
""
{=
""
if
=
""
(mroots[i].mwindow.asbinder()=
"="
wparams.token)=
""
panelparentview=
"mViews[i];"
}=
""
为activity创建一个viewrootimpl对象=
""
①root=
"new"
viewrootimpl(view.getcontext());=
""
...=
""
设置视图组件的布局参数=
""
view.setlayoutparams(wparams);=
""
(mviews=
"="
null
)=
""
index=
"1;"
mviews=
"new"
view[
1
];=
""
mroots=
"new"
viewrootimpl[
1
];=
""
mparams=
"new"
windowmanager.layoutparams[
1
];=
""
else
=
""
动态增加mviews数组长度=
""
+=
""
1
;=
""
object[]=
""
old=
"mViews;"
view[index];=
""
system.arraycopy(old,=
""
0
,=
""
mviews,=
""
index-
1
);=
""
动态增加mroots数组长度=
""
viewrootimpl[index];=
""
mroots,=
""
动态增加mparams数组长度=
""
windowmanager.layoutparams[index];=
""
mparams,=
""
index--;=
""
②mviews[index]=
"view;"
mroots[index]=
"root;"
mparams[index]=
"wparams;"
try
=
""
③root.setview(view,=
""
wparams,=
""
panelparentview);=
""
catch
=
""
(runtimeexception=
""
e)=
""
<=
""
pre=
""
>
<p>到此我们知道,当应用程序向窗口管理器中添加一个视图对象时,首先会为该视图对象创建一个ViewRootImpl对象,并且将视图对象、ViewRootImpl对象、视图布局参数分别保存到窗口管理器WindowManagerImpl得mViews、mRoots、mParams数组中,如下图所示:</p>
<p><img alt=
"\" src="
http:
//www.2cto.com/uploadfile/Collfiles/20140702/2014070208183231.jpg" width="673" height="370" style="width: 630px; height: 344.271844660194px;"><br>
<br>
</p>
<p>最后通过ViewRootImpl对象来完成视图的显示过程。</p>
<h3>ViewRootImpl构造过程</h3>
<p>frameworks\base\core\java\android\view\ViewRootImpl.java</p>
<pre
class
=
"brush:java;"
>
public
ViewRootImpl(Context context) {
...
①getWindowSession(context.getMainLooper());
mThread = Thread.currentThread();
mLocation =
new
WindowLeaked(
null
);
mLocation.fillInStackTrace();
mWidth = -
1
;
mHeight = -
1
;
mDirty =
new
Rect();
mTempRect =
new
Rect();
mVisRect =
new
Rect();
mWinFrame =
new
Rect();
②mWindow =
new
W(
this
);
mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
mInputMethodCallback =
new
InputMethodCallback(
this
);
mViewVisibility = View.GONE;
mTransparentRegion =
new
Region();
mPreviousTransparentRegion =
new
Region();
mFirst =
true
;
// true for the first time the view is added
mAdded =
false
;
mAccessibilityManager = AccessibilityManager.getInstance(context);
mAccessibilityInteractionConnectionManager =
new
AccessibilityInteractionConnectionManager();
mAccessibilityManager.addAccessibilityStateChangeListener(
mAccessibilityInteractionConnectionManager);
③mAttachInfo =
new
View.AttachInfo(sWindowSession, mWindow,
this
, mHandler,
this
);
mViewConfiguration = ViewConfiguration.get(context);
mDensity = context.getResources().getDisplayMetrics().densityDpi;
mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
mProfileRendering = Boolean.parseBoolean(
SystemProperties.get(PROPERTY_PROFILE_RENDERING,
"false"
));
④mChoreographer = Choreographer.getInstance();
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mAttachInfo.mScreenOn = powerManager.isScreenOn();
loadSystemProperties();
}</pre>
<p>在ViewRootImpl的构造函数中初始化了一些成员变量,ViewRootImpl创建了以下几个主要对象:</p>
<p>
1
) 通过getWindowSession(context.getMainLooper())得到IWindowSession的代理对象,该对象用于和WMS通信。</p>
<p>
2
) 创建了一个W本地Binder对象,用于WMS通知应用程序进程。</p>
<p>
3
) 采用单例模式创建了一个Choreographer对象,用于统一调度窗口绘图。</p>
<p>
4
) 创建ViewRootHandler对象,用于处理当前视图消息。</p>
<p>
5
) 构造一个AttachInfo对象;</p>
<p>
6
) 创建Surface对象,用于绘制当前视图,当然该Surface对象的真正创建是由WMS来完成的,只不过是WMS传递给应用程序进程的。</p>
<pre
class
=
"brush:java;"
>
private
final
Surface mSurface =
new
Surface();
final
ViewRootHandler mHandler =
new
ViewRootHandler();
</pre>
<p><img alt=
"\" src="
http:
//www.2cto.com/uploadfile/Collfiles/20140702/2014070208183232.jpg" width="672" height="368" style="width: 630px; height: 336.814404432133px;"><br>
</p>
<h4>IWindowSession代理获取过程</h4>
<p>frameworks\base\core\java\android\view\ViewRootImpl.java</p>
<pre
class
=
"brush:java;"
>
public
static
IWindowSession getWindowSession(Looper mainLooper) {
synchronized
(mStaticInit) {
if
(!mInitialized) {
try
{
//获取输入法管理器
InputMethodManager imm = InputMethodManager.getInstance(mainLooper);
//获取窗口管理器
IWindowManager windowManager = Display.getWindowManager();
//得到IWindowSession代理对象
sWindowSession = windowManager.openSession(imm.getClient(), imm.getInputContext());
float
animatorScale = windowManager.getAnimationScale(
2
);
ValueAnimator.setDurationScale(animatorScale);
mInitialized =
true
;
}
catch
(RemoteException e) {
}
}
return
sWindowSession;
}
}
</pre>
<p>以上函数通过WMS的openSession函数创建应用程序与WMS之间的连接通道,即获取IWindowSession代理对象,并将该代理对象保存到ViewRootImpl的静态成员变量sWindowSession中</p>
<pre
class
=
"brush:java;"
>
static
IWindowSession sWindowSession;</pre>
<p>因此在应用程序进程中有且只有一个IWindowSession代理对象。</p>
<p>frameworks\base\services\java\com\android\server\wm\WindowManagerService.java</p>
<pre
class
=
"brush:java;"
>
public
IWindowSession openSession(IInputMethodClient client,
IInputContext inputContext) {
if
(client ==
null
)
throw
new
IllegalArgumentException(
"null client"
);
if
(inputContext ==
null
)
throw
new
IllegalArgumentException(
"null inputContext"
);
Session session =
new
Session(
this
, client, inputContext);
return
session;
}
</pre>
<p>在WMS服务端构造了一个Session实例对象。</p>
<p><img alt=
"\" src="
http:
//www.2cto.com/uploadfile/Collfiles/20140702/2014070208183333.jpg" width="691" height="101" style="width: 630px; height: 91.7307692307692px;"><br>
</p>
<h4>AttachInfo构造过程</h4>
<p>frameworks\base\core\java\android\view\ View.java </p>
<pre
class
=
"brush:java;"
>AttachInfo(IWindowSession session, IWindow window,
ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer) {
mSession = session;
//IWindowSession代理对象,用于与WMS通信
mWindow = window;
//W对象
mWindowToken = window.asBinder();
//W本地Binder对象
mViewRootImpl = viewRootImpl;
//ViewRootImpl实例
mHandler = handler;
//ViewRootHandler对象
mRootCallbacks = effectPlayer;
//ViewRootImpl实例
}
</pre>
<h4>Choreographer机制</h4>
<p>在Android4.
1
之后增加了Choreographer机制,用于同Vsync机制配合,实现统一调度界面绘图.</p>
<h5>Choreographer构造过程</h5>
<p>frameworks\base\core\java\android\view\Choreographer.java</p>
<pre
class
=
"brush:java;"
>
public
static
Choreographer getInstance() {
return
sThreadInstance.get();
}
</pre><pre
class
=
"brush:java;"
>
private
static
final
ThreadLocal<choreographer> sThreadInstance =
new
ThreadLocal<choreographer>() {
@Override
protected
Choreographer initialValue() {
Looper looper = Looper.myLooper();
if
(looper ==
null
) {
throw
new
IllegalStateException(
"The current thread must have a looper!"
);
}
return
new
Choreographer(looper);
}
};
</choreographer></choreographer></pre>
<p>为调用线程创建一个Choreographer实例,调用线程必须具备消息循环功能,因为ViewRootImpl对象的构造是在应用程序进程的UI主线程中执行的,因此创建的Choreographer对象将使用UI线程消息队列。</p>
<pre
class
=
"brush:java;"
>
private
Choreographer(Looper looper) {
mLooper = looper;
//创建消息处理Handler
mHandler =
new
FrameHandler(looper);
//如果系统使用了Vsync机制,则注册一个FrameDisplayEventReceiver接收器
mDisplayEventReceiver = USE_VSYNC ?
new
FrameDisplayEventReceiver(looper) :
null
;
mLastFrameTimeNanos = Long.MIN_VALUE;
//屏幕刷新周期
mFrameIntervalNanos = (
long
)(
1000000000
/
new
Display(Display.DEFAULT_DISPLAY,
null
).getRefreshRate());
//创建回调数组
mCallbackQueues =
new
CallbackQueue[CALLBACK_LAST +
1
];
//初始化数组
for
(
int
i =
0
; i <= CALLBACK_LAST; i++) {
mCallbackQueues[i] =
new
CallbackQueue();
}
}
</pre>
<p>变量USE_VSYNC用于表示系统是否是用了Vsync同步机制,该值是通过读取系统属性debug.choreographer.vsync来获取的。如果系统使用了Vsync同步机制,则创建一个FrameDisplayEventReceiver对象用于请求并接收Vsync事件,最后Choreographer创建了一个大小为
3
的CallbackQueue队列数组,用于保存不同类型的Callback。</p>
<h5>添加回调过程</h5>
<p>frameworks\base\core\java\android\view\Choreographer.java</p>
<pre
class
=
"brush:java;"
>
public
void
postCallback(
int
callbackType, Runnable action, Object token) {
postCallbackDelayed(callbackType, action, token,
0
);
}
</pre>
<p> </p>
<pre
class
=
"brush:java;"
>
public
void
postCallbackDelayed(
int
callbackType,
Runnable action, Object token,
long
delayMillis) {
if
(action ==
null
) {
throw
new
IllegalArgumentException(
"action must not be null"
);
}
if
(callbackType <
0
|| callbackType > CALLBACK_LAST) {
throw
new
IllegalArgumentException(
"callbackType is invalid"
);
}
postCallbackDelayedInternal(callbackType, action, token, delayMillis);
}
</pre>
<p> </p>
<pre
class
=
"brush:java;"
>
private
void
postCallbackDelayedInternal(
int
callbackType,
Object action, Object token,
long
delayMillis) {
synchronized
(mLock) {
final
long
now = SystemClock.uptimeMillis();
final
long
dueTime = now + delayMillis;
//将要执行的回调封装成CallbackRecord对象,保存到mCallbackQueues数组中
mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
//函数执行时间到
if
(dueTime <= now) {
scheduleFrameLocked(now);
}
else
{
//通过异步消息方式实现函数延时执行
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
msg.arg1 = callbackType;
msg.setAsynchronous(
true
);
mHandler.sendMessageAtTime(msg, dueTime);
}
}
}
</pre>
<p> </p>
<pre
class
=
"brush:java;"
>
private
final
class
FrameHandler
extends
Handler {
@Override
public
void
handleMessage(Message msg) {
switch
(msg.what) {
case
MSG_DO_SCHEDULE_CALLBACK:
doScheduleCallback(msg.arg1);
break
;
}
}
}
</pre>
<p> </p>
<pre
class
=
"brush:java;"
>
void
doScheduleCallback(
int
callbackType) {
synchronized
(mLock) {
if
(!mFrameScheduled) {
final
long
now = SystemClock.uptimeMillis();
if
(mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
scheduleFrameLocked(now);
}
}
}
}
</pre>
<p> </p>
<pre
class
=
"brush:java;"
>
private
void
scheduleFrameLocked(
long
now) {
if
(!mFrameScheduled) {
mFrameScheduled =
true
;
//检查是否使用了Vsync机制
if
(USE_VSYNC) {
//如果当前线程具备消息循环,则直接请求VSync信号
if
(isRunningOnLooperThreadLocked()) {
scheduleVsyncLocked();
}
else
{
//如果当前线程不具备消息循环,则通过主线程请求VSync信号
Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
msg.setAsynchronous(
true
);
mHandler.sendMessageAtFrontOfQueue(msg);
}
}
else
{
//如果系统没有使用VSync机制,则使用异步消息延时执行屏幕刷新
final
long
nextFrameTime = Math.max(
mLastFrameTimeNanos / NANOS_PER_MS + sFrameDelay, now);
Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
msg.setAsynchronous(
true
);
mHandler.sendMessageAtTime(msg, nextFrameTime);
}
}
}
</pre>
<p>在该函数中考虑了两种情况,一种是系统没有使用Vsync机制,在这种情况下,首先根据屏幕刷新频率计算下一次刷新时间,通过异步消息方式延时执行doFrame()函数实现屏幕刷新。如果系统使用了Vsync机制,并且当前线程具备消息循环,则直接请求Vsync信号,否则就通过主线程来请求Vsync信号。FrameDisplayEventReceiver对象用于请求并接收Vsync信号,当Vsync信号到来时,系统会自动调用其onVsync()函数,在该回调函数中执行doFrame()实现屏幕刷新。</p>
<p align=
"center"
><img alt=
"\" src="
http:
//www.2cto.com/uploadfile/Collfiles/20140702/2014070208183334.jpg" style="height: 560px; width: 434.255874673629px;"></p>
<p>当VSYNC信号到达时,Choreographer doFrame()函数被调用</p>
<pre
class
=
"brush:java;"
>
void
doFrame(
long
frameTimeNanos,
int
frame) {
final
long
startNanos;
synchronized
(mLock) {
if
(!mFrameScheduled) {
return
;
// no work to do
}
//保存起始时间
startNanos = System.nanoTime();
//由于Vsync事件处理采用的是异步方式,因此这里计算消息发送与函数调用开始之间所花费的时间
final
long
jitterNanos = startNanos - frameTimeNanos;
//如果线程处理该消息的时间超过了屏幕刷新周期
if
(jitterNanos >= mFrameIntervalNanos) {
//计算函数调用期间所错过的帧数
final
long
skippedFrames = jitterNanos / mFrameIntervalNanos;
if
(skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) {
Log.i(TAG,
"Skipped "
+ skippedFrames +
" frames! "
+
"The application may be doing too much work on its main thread."
);
}
final
long
lastFrameOffset = jitterNanos % mFrameIntervalNanos;
frameTimeNanos = startNanos - lastFrameOffset;
}
//如果frameTimeNanos小于一个屏幕刷新周期,则重新请求VSync信号
if
(frameTimeNanos < mLastFrameTimeNanos) {
scheduleVsyncLocked();
return
;
}
mFrameScheduled =
false
;
mLastFrameTimeNanos = frameTimeNanos;
}
//分别回调CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL事件
doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
}
</pre>
<p align=
"center"
><img alt=
"\" src="
http:
//www.2cto.com/uploadfile/Collfiles/20140702/2014070208183335.jpg" style="width: 627px; height: 187px;"></p>
<p><br>
Choreographer类中分别定义了CallbackRecord、CallbackQueue内部类,CallbackQueue是一个按时间先后顺序保存CallbackRecord的单向循环链表。</p>
<p align=
"center"
><img alt=
"\" src="
http:
//www.2cto.com/uploadfile/Collfiles/20140702/2014070208183336.jpg" style="width: 495px; height: 138px;"></p>
<p>在Choreographer中定义了三个CallbackQueue队列,用数组mCallbackQueues表示,用于分别保存CALLBACK_INPUT、CALLBACK_ANIMATION、CALLBACK_TRAVERSAL这三种类型的Callback,当调用Choreographer类的postCallback()函数时,就是往指定类型的CallbackQueue队列中通过addCallbackLocked()函数添加一个CallbackRecord项:首先构造一个CallbackRecord对象,然后按时间先后顺序插入到CallbackQueue链表中。从代码注释中,我们可以知道CALLBACK_INPUT是指输入回调,该回调优先级最高,首先得到执行,而CALLBACK_TRAVERSAL是指处理布局和绘图的回调,只有在所有异步消息都执行完后才得到执行,CALLBACK_ANIMATION是指动画回调,比CALLBACK_TRAVERSAL优先执行,从doFrame()函数中的doCallbacks调用就能印证这点。</p>
<pre
class
=
"brush:java;"
>doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
</pre>
<p>当Vsync事件到来时,顺序执行CALLBACK_INPUT、CALLBACK_ANIMATION和CALLBACK_TRAVERSAL对应CallbackQueue队列中注册的回调。</p>
<pre
class
=
"brush:java;"
>
void
doCallbacks(
int
callbackType,
long
frameTimeNanos) {
CallbackRecord callbacks;
synchronized
(mLock) {
final
long
now = SystemClock.uptimeMillis();
//从指定类型的CallbackQueue队列中查找执行时间到的CallbackRecord
callbacks = mCallbackQueues[callbackType].extractDueCallbacksLocked(now);
if
(callbacks ==
null
) {
return
;
}
mCallbacksRunning =
true
;
}
try
{
//由于CallbackQueues是按时间先后顺序排序的,因此遍历执行所有时间到的CallbackRecord
for
(CallbackRecord c = callbacks; c !=
null
; c = c.next) {
c.run(frameTimeNanos);
}
}
finally
{
synchronized
(mLock) {
mCallbacksRunning =
false
;
do
{
final
CallbackRecord next = callbacks.next;
recycleCallbackLocked(callbacks);
callbacks = next;
}
while
(callbacks !=
null
);
}
}
}
</pre>
<p>该函数就是按时间顺序先后执行到时的CallbackRecord</p>
<pre
class
=
"brush:java;"
>
private
static
final
class
CallbackRecord {
public
CallbackRecord next;
public
long
dueTime;
public
Object action;
// Runnable or FrameCallback
public
Object token;
public
void
run(
long
frameTimeNanos) {
if
(token == FRAME_CALLBACK_TOKEN) {
((FrameCallback)action).doFrame(frameTimeNanos);
}
else
{
((Runnable)action).run();
}
}
}
</pre>
<p>我们知道Choreographer对外提供了两个接口函数用于注册指定的Callback,postCallback()用于注册Runnable对象,而postFrameCallback()函数用于注册FrameCallback对象,无论注册的是Runnable对象还是FrameCallback对象,在CallbackRecord对象中统一装箱为Object类型。在执行其回调函数时,就需要区别这两种对象类型,如果注册的是Runnable对象,则调用其run()函数,如果注册的是FrameCallback对象,则调用它的doFrame()函数。</p>
<p align=
"center"
><img alt=
"\" src="
http:
//www.2cto.com/uploadfile/Collfiles/20140702/2014070208183337.jpg" style="width: 485px; height: 288px;"></p>
<h5>Vsync请求过程</h5>
<p>我们知道在Choreographer构造函数中,构造了一个FrameDisplayEventReceiver对象,用于请求并接收Vsync信号,Vsync信号请求过程如下:</p>
<pre
class
=
"brush:java;"
>
private
void
scheduleVsyncLocked() {
//申请Vsync信号
mDisplayEventReceiver.scheduleVsync();
}</pre>
<p>FrameDisplayEventReceiver继承于DisplayEventReceiver类,Vsync请求在DisplayEventReceiver中实现。</p>
<p>frameworks\base\core\java\android\view\ DisplayEventReceiver.java </p>
<pre
class
=
"brush:java;"
>
public
void
scheduleVsync() {
if
(mReceiverPtr ==
0
) {
Log.w(TAG,
"Attempted to schedule a vertical sync pulse but the display event "
+
"receiver has already been disposed."
);
}
else
{
//通过Jni方式调用native层的NativeDisplayEventReceiver对象来请求VSync
nativeScheduleVsync(mReceiverPtr);
}
}
</pre>
<p>frameworks\base\core\jni\ android_view_DisplayEventReceiver.cpp</p>
<pre
class
=
"brush:java;"
>
static
void
nativeScheduleVsync(JNIEnv* env, jclass clazz, jint receiverPtr) {
//得到NativeDisplayEventReceiver对象指针
sp<nativedisplayeventreceiver> receiver =
reinterpret_cast<nativedisplayeventreceiver*>(receiverPtr);
//通过NativeDisplayEventReceiver请求VSync
status_t status = receiver->scheduleVsync();
if
(status) {
String8 message;
message.appendFormat(
"Failed to schedule next vertical sync pulse. status=%d"
, status);
jniThrowRuntimeException(env, message.string());
}
}
</nativedisplayeventreceiver*></nativedisplayeventreceiver></pre>
<p align=
"left"
> </p>
<pre
class
=
"brush:java;"
>status_t NativeDisplayEventReceiver::scheduleVsync() {
if
(!mWaitingForVsync) {
ALOGV(
"receiver %p ~ Scheduling vsync."
,
this
);
// Drain all pending events.
nsecs_t vsyncTimestamp;
uint32_t vsyncCount;
readLastVsyncMessage(&vsyncTimestamp, &vsyncCount);
status_t status = mReceiver.requestNextVsync();
if
(status) {
ALOGW(
"Failed to request next vsync, status=%d"
, status);
return
status;
}
mWaitingForVsync =
true
;
}
return
OK;
}
</pre>
<p align=
"left"
>VSync请求过程又转交给了DisplayEventReceiver</p>
<p>frameworks\
native
\libs\gui\ DisplayEventReceiver.cpp </p>
<pre
class
=
"brush:java;"
>status_t DisplayEventReceiver::requestNextVsync() {
if
(mEventConnection != NULL) {
mEventConnection->requestNextVsync();
return
NO_ERROR;
}
return
NO_INIT;
}
</pre>
<p>这里又通过IDisplayEventConnection接口来请求Vsync信号,IDisplayEventConnection实现了Binder通信框架,可以跨进程调用,因为Vsync信号请求进程和Vsync产生进程有可能不在同一个进程空间,因此这里就借助IDisplayEventConnection接口来实现。下面通过图来梳理Vsync请求的调用流程:</p>
<p align=
"center"
><img alt=
"\" src="
http:
//www.2cto.com/uploadfile/Collfiles/20140702/2014070208183338.png" style="width: 231px; height: 241px;"></p>
<h3>视图View添加过程</h3>
<p>窗口管理器WindowManagerImpl为当前添加的窗口创建好各种对象后,调用ViewRootImpl的setView函数向WMS服务添加一个窗口对象。</p>
<pre
class
=
"brush:java;"
>
public
void
setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized
(
this
) {
if
(mView ==
null
) {
//将DecorView保存到ViewRootImpl的成员变量mView中
mView = view;
mFallbackEventHandler.setView(view);
mWindowAttributes.copyFrom(attrs);
attrs = mWindowAttributes;
mClientWindowLayoutFlags = attrs.flags;
setAccessibilityFocus(
null
,
null
);
//DecorView实现了RootViewSurfaceTaker接口
if
(view
instanceof
RootViewSurfaceTaker) {
mSurfaceHolderCallback =
((RootViewSurfaceTaker)view).willYouTakeTheSurface();
if
(mSurfaceHolderCallback !=
null
) {
mSurfaceHolder =
new
TakenSurfaceHolder();
mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
}
}
...
//同时将DecorView保存到mAttachInfo中
mAttachInfo.mRootView = view;
mAttachInfo.mScalingRequired = mTranslator !=
null
;
mAttachInfo.mApplicationScale = mTranslator ==
null
?
1
.0f : mTranslator.applicationScale;
if
(panelParentView !=
null
) {
mAttachInfo.mPanelParentWindowToken
= panelParentView.getApplicationWindowToken();
}
...
//在添加窗口前进行UI布局
①requestLayout();
if
((mWindowAttributes.inputFeatures& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) ==
0
) {
mInputChannel =
new
InputChannel();
}
try
{
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes =
true
;
collectViewAttributes();
//将窗口添加到WMS服务中,mWindow为W本地Binder对象,通过Binder传输到WMS服务端后,变为IWindow代理对象
②res = sWindowSession.add(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mAttachInfo.mContentInsets,
mInputChannel);
}
catch
(RemoteException e) {
...
}
...
//建立窗口消息通道
if
(view
instanceof
RootViewSurfaceTaker) {
mInputQueueCallback =
((RootViewSurfaceTaker)view).willYouTakeTheInputQueue();
}
if
(mInputChannel !=
null
) {
if
(mInputQueueCallback !=
null
) {
mInputQueue =
new
InputQueue(mInputChannel);
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
else
{
mInputEventReceiver =
new
WindowInputEventReceiver(mInputChannel,Looper.myLooper());
}
}
...
}
}
}
</pre>
<p align=
"left"
>通过前面的分析可以知道,用户自定义的UI作为一个子View被添加到DecorView中,然后将顶级视图DecorView添加到应用程序进程的窗口管理器中,窗口管理器首先为当前添加的View创建一个ViewRootImpl对象、一个布局参数对象ViewGroup.LayoutParams,然后将这三个对象分别保存到当前应用程序进程的窗口管理器WindowManagerImpl中,最后通过ViewRootImpl对象将当前视图对象注册到WMS服务中。<br>
<img alt=
"\" src="
http:
//www.2cto.com/uploadfile/Collfiles/20140702/2014070208183339.jpg" width="676" height="517" style="width: 630px; height: 468.125px;"></p>
<p>ViewRootImpl的setView函数向WMS服务添加一个窗口对象过程:</p>
<p>
1
) requestLayout()在应用程序进程中进行窗口UI布局;</p>
<p>
2
) WindowSession.add()向WMS服务注册一个窗口对象;</p>
<p>
3
) 注册应用程序进程端的消息接收通道;</p>
<h4>窗口UI布局过程</h4>
<p><img src=
"http://www.2cto.com/uploadfile/Collfiles/20140702/2014070208183440.jpg"
width=
"707"
height=
"463"
alt=
"\" style="
width: 630px; height:
418
.751486325803px;"></p>
<p>framewZ喎�
"http://www.2cto.com/kf/ware/vc/"
target=
"_blank"
class
=
"keylink"
>vcmtzXGJhc2VcY29yZVxqYXZhXGFuZHJvaWRcdmlld1xWaWV3Um9vdEltcGwuamF2YTwvcD4KPHByZSBjbGFzcz0=
"brush:java;"
>
public
void
requestLayout() {
//检查当前线程是否是UI线程
checkThread();
//标识当前正在请求UI布局
mLayoutRequested =
true
;
scheduleTraversals();
}
</p></count;>
窗口布局过程必须在UI线程中进行,因此该函数首先检查调用requestLayout()函数的线程是否为创建ViewRootImpl对象的线程。然后调用scheduleTraversals()函数启动Choreographer的Callback遍历过程。
void
scheduleTraversals() {
if
(!mTraversalScheduled) {
mTraversalScheduled =
true
;
//暂停UI线程消息队列对同步消息的处理
mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
//向Choreographer注册一个类型为CALLBACK_TRAVERSAL的回调,用于处理UI绘制
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable,
null
);
//向Choreographer注册一个类型为CALLBACK_INPUT的回调,用于处理输入事件
scheduleConsumeBatchedInput();
}
}
关于Choreographer的postCallback()用法在前面进行了详细的介绍,当Vsync事件到来时,mTraversalRunnable对象的run()函数将被调用。
frameworks\base\core\java\android\view\ViewRootImpl.java
final
TraversalRunnable mTraversalRunnable =
new
TraversalRunnable();
final
class
TraversalRunnable
implements
Runnable {
@Override
public
void
run() {
doTraversal();
}
}
mTraversalRunnable对象的类型为TraversalRunnable,该类实现了Runnable接口,在其run()函数中调用了doTraversal()函数来完成窗口布局。
void
doTraversal() {
if
(mTraversalScheduled) {
mTraversalScheduled =
false
;
mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
if
(mProfile) {
Debug.startMethodTracing(
"ViewAncestor"
);
}
Trace.traceBegin(Trace.TRACE_TAG_VIEW,
"performTraversals"
);
try
{
performTraversals();
}
finally
{
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
if
(mProfile) {
Debug.stopMethodTracing();
mProfile =
false
;
}
}
}
- Android应用程序窗口设计框架二
- Android应用程序窗口设计框架介绍
- Android应用程序窗口设计框架 一
- Android应用程序窗口设计框架三
- Android应用程序窗口设计框架四
- Android应用程序窗口设计框架介绍
- Android 应用程序框架设计
- 应用程序框架设计(2):SW系统的窗口类
- 应用程序框架设计(2):SW系统的窗口类
- 应用程序框架设计(2):SW系统的窗口类
- 应用程序框架设计(2):SW系统的窗口类
- 应用程序框架设计(2):SW系统的窗口类
- 应用程序框架设计(2):SW系统的窗口类
- 应用程序框架设计(2):SW系统的窗口类
- Android基础知识二(应用程序框架)
- android应用程序窗口框架学习(4)-从setcontentview说起
- 应用程序主窗口-主窗口框架
- Android应用程序窗口
- FindBugs作为eclipse插件和ant工具的安装、使用
- jquery鼠标悬停图片上下滚动切换
- GetSchema 参数解析
- SVN地址修改
- Java 实现各种排序算法并测试排序效率
- Android应用程序窗口设计框架二
- 工具目录
- android----问题解决Dex Loader] Unable to execute dex: Multiple dex files define Lcom/sina/sso/RemoteSSO;
- 加班那些事
- CentOS6.3如何安装中文输入法?
- CSerialPort串口类最新修正版(解决关闭死锁问题)2014-01-11
- byebye2014,hello2015
- 接口配置锦囊妙计之三----端口自协商
- 自闭症的临床表现