Android应用程序窗口设计框架三
来源:互联网 发布:五笔练习软件 编辑:程序博客网 时间:2024/05/23 01:57
performTraversals函数相当复杂,其主要实现以下几个重要步骤:
1.执行窗口测量;
2.执行窗口注册;
3.执行窗口布局;
4.执行窗口绘图;
private
void
performTraversals() {
// cache mView since it is used so much below...
final
View host = mView;
if
(host ==
null
|| !mAdded)
return
;
mWillDrawSoon =
true
;
boolean
windowSizeMayChange =
false
;
boolean
newSurface =
false
;
boolean
surfaceChanged =
false
;
WindowManager.LayoutParams lp = mWindowAttributes;
int
desiredWindowWidth;
int
desiredWindowHeight;
final
View.AttachInfo attachInfo = mAttachInfo;
final
int
viewVisibility = getHostVisibility();
boolean
viewVisibilityChanged = mViewVisibility != viewVisibility
|| mNewSurfaceNeeded;
WindowManager.LayoutParams params =
null
;
if
(mWindowAttributesChanged) {
mWindowAttributesChanged =
false
;
surfaceChanged =
true
;
params = lp;
}
...
/****************执行窗口测量******************/
boolean
layoutRequested = mLayoutRequested && !mStopped;
if
(layoutRequested) {
...
// Ask host how big it wants to be
windowSizeMayChange |= measureHierarchy(host, lp, res,
desiredWindowWidth, desiredWindowHeight);
}
...
/****************向WMS服务添加窗口******************/
if
(mFirst || windowShouldResize || insetsChanged ||
viewVisibilityChanged || params !=
null
) {
...
try
{
final
int
surfaceGenerationId = mSurface.getGenerationId();
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
...
}
catch
(RemoteException e) {
}
...
if
(!mStopped) {
boolean
focusChangedDueToTouchMode = ensureTouchModeLocally(
(relayoutResult&WindowManagerImpl.RELAYOUT_RES_IN_TOUCH_MODE) !=
0
);
if
(focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
|| mHeight != host.getMeasuredHeight() || contentInsetsChanged) {
...
// Ask host how big it wants to be
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
...
}
}
}
/****************执行窗口布局******************/
final
boolean
didLayout = layoutRequested && !mStopped;
boolean
triggerGlobalLayoutListener = didLayout
|| attachInfo.mRecomputeGlobalAttributes;
if
(didLayout) {
performLayout();
...
}
...
/****************查找窗口焦点******************/
boolean
skipDraw =
false
;
if
(mFirst) {
// handle first focus request
if
(DEBUG_INPUT_RESIZE) Log.v(TAG,
"First: mView.hasFocus()="
+ mView.hasFocus());
if
(mView !=
null
) {
if
(!mView.hasFocus()) {
mView.requestFocus(View.FOCUS_FORWARD);
mFocusedView = mRealFocusedView = mView.findFocus();
if
(DEBUG_INPUT_RESIZE) Log.v(TAG,
"First: requested focused view="
+ mFocusedView);
}
else
{
mRealFocusedView = mView.findFocus();
if
(DEBUG_INPUT_RESIZE) Log.v(TAG,
"First: existing focused view="
+ mRealFocusedView);
}
}
if
((relayoutResult&WindowManagerImpl.RELAYOUT_RES_ANIMATING) !=
0
) {
// The first time we relayout the window, if the system is
// doing window animations, we want to hold of on any future
// draws until the animation is done.
mWindowsAnimating =
true
;
}
}
else
if
(mWindowsAnimating) {
skipDraw =
true
;
}
/****************执行窗口绘制******************/
mFirst =
false
;
mWillDrawSoon =
false
;
mNewSurfaceNeeded =
false
;
mViewVisibility = viewVisibility;
...
boolean
cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw() ||
viewVisibility != View.VISIBLE;
if
(!cancelDraw && !newSurface) {
if
(!skipDraw || mReportNextDraw) {
if
(mPendingTransitions !=
null
&& mPendingTransitions.size() >
0
) {
for
(
int
i =
0
; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).startChangingAnimations();
}
mPendingTransitions.clear();
}
performDraw();
}
}
else
{
if
(viewVisibility == View.VISIBLE) {
// Try again
scheduleTraversals();
}
else
if
(mPendingTransitions !=
null
&& mPendingTransitions.size() >
0
) {
for
(
int
i =
0
; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).endChangingAnimations();
}
mPendingTransitions.clear();
}
}
}
performMeasure
frameworks\base\core\java\android\view\ViewRootImpl.java
private
void
performMeasure(
int
childWidthMeasureSpec,
int
childHeightMeasureSpec) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW,
"measure"
);
try
{
mView.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
finally
{
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
relayoutWindow
frameworks\base\core\java\android\view\ViewRootImpl.java
private
int
relayoutWindow(WindowManager.LayoutParams params,
int
viewVisibility,
boolean
insetsPending)
throws
RemoteException {
...
int
relayoutResult = sWindowSession.relayout(
mWindow, mSeq, params,
(
int
) (mView.getMeasuredWidth() * appScale +
0
.5f),
(
int
) (mView.getMeasuredHeight() * appScale +
0
.5f),
viewVisibility, insetsPending ? WindowManagerImpl.RELAYOUT_INSETS_PENDING :
0
,
mWinFrame, mPendingContentInsets, mPendingVisibleInsets,
mPendingConfiguration, mSurface);
...
return
relayoutResult;
}
这里通过前面获取的IWindowSession代理对象请求WMS服务执行窗口布局,mSurface是ViewRootImpl的成员变量
private
final
Surface mSurface =
new
Surface();
frameworks\base\core\java\android\view\ Surface.java
public
Surface() {
checkHeadless();
if
(DEBUG_RELEASE) {
mCreationStack =
new
Exception();
}
mCanvas =
new
CompatibleCanvas();
}
该Surface构造函数仅仅创建了一个CompatibleCanvas对象,并没有对该Surface进程native层的初始化,到此我们知道应用程序进程为每个窗口对象都创建了一个Surface对象。并且将该Surface通过跨进程方式传输给WMS服务进程,我们知道,在Android系统中,如果一个对象需要在不同进程间传输,必须实现Parcelable接口,Surface类正好实现了Parcelable接口。ViewRootImpl通过IWindowSession接口请求WMS的完整过程如下:
frameworks\base\core\java\android\view\IWindowSession.java$ Proxy
public
int
relayout(android.view.IWindow window,
int
seq,
android.view.WindowManager.LayoutParams attrs,
int
requestedWidth,
int
requestedHeight,
int
viewVisibility,
int
flags,
android.graphics.Rect outFrame,
android.graphics.Rect outOverscanInsets,
android.graphics.Rect outContentInsets,
android.graphics.Rect outVisibleInsets,
android.content.res.Configuration outConfig,
android.view.Surface outSurface)
throws
android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int
_result;
try
{
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((window !=
null
)) ? (window.asBinder()): (
null
)));
_data.writeInt(seq);
if
((attrs !=
null
)) {
_data.writeInt(
1
);
attrs.writeToParcel(_data,
0
);
}
else
{
_data.writeInt(
0
);
}
_data.writeInt(requestedWidth);
_data.writeInt(requestedHeight);
_data.writeInt(viewVisibility);
_data.writeInt(flags);
mRemote.transact(Stub.TRANSACTION_relayout, _data, _reply,
0
);
_reply.readException();
_result = _reply.readInt();
if
((
0
!= _reply.readInt())) {
outFrame.readFromParcel(_reply);
}
if
((
0
!= _reply.readInt())) {
outOverscanInsets.readFromParcel(_reply);
}
if
((
0
!= _reply.readInt())) {
outContentInsets.readFromParcel(_reply);
}
if
((
0
!= _reply.readInt())) {
outVisibleInsets.readFromParcel(_reply);
}
if
((
0
!= _reply.readInt())) {
outConfig.readFromParcel(_reply);
}
if
((
0
!= _reply.readInt())) {
outSurface.readFromParcel(_reply);
}
}
finally
{
_reply.recycle();
_data.recycle();
}
return
_result;
}
从该函数的实现可以看出,应用程序进程中创建的Surface对象并没有传递到WMS服务进程,只是读取WMS服务进程返回来的Surface。那么WMS服务进程是如何响应应用程序进程布局请求的呢?
frameworks\base\core\java\android\view\IWindowSession.java$ Stub
public
boolean
onTransact(
int
code, android.os.Parcel data,
android.os.Parcel reply,
int
flags)
throws
android.os.RemoteException {
switch
(code) {
case
TRANSACTION_relayout: {
data.enforceInterface(DESCRIPTOR);
android.view.IWindow _arg0;
_arg0 = android.view.IWindow.Stub.asInterface(data.readStrongBinder());
int
_arg1;
_arg1 = data.readInt();
android.view.WindowManager.LayoutParams _arg2;
if
((
0
!= data.readInt())) {
_arg2 = android.view.WindowManager.LayoutParams.CREATOR
.createFromParcel(data);
}
else
{
_arg2 =
null
;
}
int
_arg3;
_arg3 = data.readInt();
int
_arg4;
_arg4 = data.readInt();
int
_arg5;
_arg5 = data.readInt();
int
_arg6;
_arg6 = data.readInt();
android.graphics.Rect _arg7;
_arg7 =
new
android.graphics.Rect();
android.graphics.Rect _arg8;
_arg8 =
new
android.graphics.Rect();
android.graphics.Rect _arg9;
_arg9 =
new
android.graphics.Rect();
android.graphics.Rect _arg10;
_arg10 =
new
android.graphics.Rect();
android.content.res.Configuration _arg11;
_arg11 =
new
android.content.res.Configuration();
android.view.Surface _arg12;
_arg12 =
new
android.view.Surface();
int
_result =
this
.relayout(_arg0, _arg1, _arg2, _arg3, _arg4,
_arg5, _arg6, _arg7, _arg8, _arg9, _arg10, _arg11, _arg12);
reply.writeNoException();
reply.writeInt(_result);
if
((_arg7 !=
null
)) {
reply.writeInt(
1
);
_arg7.writeToParcel(reply,
android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else
{
reply.writeInt(
0
);
}
if
((_arg8 !=
null
)) {
reply.writeInt(
1
);
_arg8.writeToParcel(reply,
android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else
{
reply.writeInt(
0
);
}
if
((_arg9 !=
null
)) {
reply.writeInt(
1
);
_arg9.writeToParcel(reply,
android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else
{
reply.writeInt(
0
);
}
if
((_arg10 !=
null
)) {
reply.writeInt(
1
);
_arg10.writeToParcel(reply,
android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else
{
reply.writeInt(
0
);
}
if
((_arg11 !=
null
)) {
reply.writeInt(
1
);
_arg11.writeToParcel(reply,
android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else
{
reply.writeInt(
0
);
}
if
((_arg12 !=
null
)) {
reply.writeInt(
1
);
_arg12.writeToParcel(reply,
android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
else
{
reply.writeInt(
0
);
}
return
true
;
}
}
}
该函数可以看出,WMS服务在响应应用程序进程请求添加窗口时,首先在当前进程空间创建一个Surface对象,然后调用Session的relayout()函数进一步完成窗口添加过程,最后将WMS服务中创建的Surface返回给应用程序进程。
到目前为止,在应用程序进程和WMS服务进程分别创建了一个Surface对象,但是他们调用的都是Surface的无参构造函数,在该构造函数中并未真正初始化native层的Surface,那native层的Surface是在那里创建的呢?
frameworks\base\services\java\com\android\server\wm\ Session.java
public
int
relayout(IWindow window,
int
seq, WindowManager.LayoutParams attrs,
int
requestedWidth,
int
requestedHeight,
int
viewFlags,
int
flags, Rect outFrame, Rect outContentInsets,
Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {
int
res = mService.relayoutWindow(
this
, window, seq, attrs,
requestedWidth, requestedHeight, viewFlags, flags,
outFrame, outContentInsets, outVisibleInsets,
outConfig, outSurface);
return
res;
}
frameworks\base\services\java\com\android\server\wm\ WindowManagerService.java
public
int
relayoutWindow(Session session, IWindow client,
int
seq,
WindowManager.LayoutParams attrs,
int
requestedWidth,
int
requestedHeight,
int
viewVisibility,
int
flags,
Rect outFrame, Rect outContentInsets,
Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {
...
synchronized
(mWindowMap) {
// TODO(cmautner): synchronize on mAnimator or win.mWinAnimator.
WindowState win = windowForClientLocked(session, client,
false
);
if
(win ==
null
) {
return
0
;
}
...
if
(viewVisibility == View.VISIBLE &&
(win.mAppToken ==
null
|| !win.mAppToken.clientHidden)) {
...
try
{
if
(!win.mHasSurface) {
surfaceChanged =
true
;
}
//创建Surface
Surface surface = winAnimator.createSurfaceLocked();
if
(surface !=
null
) {
outSurface.copyFrom(surface);
}
else
{
outSurface.release();
}
}
catch
(Exception e) {
...
}
...
}
...
}
...
}
frameworks\base\services\java\com\android\server\wm\WindowStateAnimator.java
Surface createSurfaceLocked() {
if
(mSurface ==
null
) {
...
try
{
...
if
(DEBUG_SURFACE_TRACE) {
mSurface =
new
SurfaceTrace(
mSession.mSurfaceSession, mSession.mPid,
attrs.getTitle().toString(),
0
, w, h, format, flags);
}
else
{
mSurface =
new
Surface(
mSession.mSurfaceSession, mSession.mPid,
attrs.getTitle().toString(),
0
, w, h, format, flags);
}
mWin.mHasSurface =
true
;
}
catch
(Surface.OutOfResourcesException e) {
...
}
Surface.openTransaction();
...
}
return
mSurface;
}
Surface创建过程
frameworks\base\core\java\android\view\Surface.java
public
Surface(SurfaceSession s,
int
pid, String name,
int
display,
int
w,
int
h,
int
format,
int
flags)
throws
OutOfResourcesException {
checkHeadless();
if
(DEBUG_RELEASE) {
mCreationStack =
new
Exception();
}
mCanvas =
new
CompatibleCanvas();
init(s,pid,name,display,w,h,format,flags);
mName = name;
}
frameworks\base\core\jni\ android_view_Surface.cpp
static
void
Surface_init(
JNIEnv* env, jobject clazz,
jobject session,
jint, jstring jname, jint dpy, jint w, jint h, jint format, jint flags)
{
if
(session == NULL) {
doThrowNPE(env);
return
;
}
SurfaceComposerClient* client =
(SurfaceComposerClient*)env->GetIntField(session, sso.client);
sp<surfacecontrol> surface;
if
(jname == NULL) {
surface = client->createSurface(dpy, w, h, format, flags);
}
else
{
const
jchar* str = env->GetStringCritical(jname,
0
);
const
String8 name(str, env->GetStringLength(jname));
env->ReleaseStringCritical(jname, str);
surface = client->createSurface(name, dpy, w, h, format, flags);
}
if
(surface ==
0
) {
jniThrowException(env, OutOfResourcesException, NULL);
return
;
}
setSurfaceControl(env, clazz, surface);
}</surfacecontrol>
到此才算真正创建了一个可用于绘图的Surface,从上面的分析我们可以看出,在WMS服务进程端,其实创建了两个Java层的Surface对象,第一个Surface使用了无参构造函数,仅仅构造一个Surface对象而已,而第二个Surface却使用了有参构造函数,参数指定了图象宽高等信息,这个Java层Surface对象还会在native层请求SurfaceFlinger创建一个真正能用于绘制图象的native层Surface。最后通过浅拷贝的方式将第二个Surface复制到第一个Surface中,最后通过writeToParcel方式写回到应用程序进程。
到目前为止,应用程序和WMS一共创建了3个Java层Surface对象,如上图所示,而真正能用于绘图的Surface只有3号,那么3号Surface与2号Surface之间是什么关系呢?outSurface.copyFrom(surface)
frameworks\base\core\jni\ android_view_Surface.cpp
static
void
Surface_copyFrom(JNIEnv* env, jobject clazz, jobject other)
{
if
(clazz == other)
return
;
if
(other == NULL) {
doThrowNPE(env);
return
;
}
//得到当前Surface所引用的SurfaceControl对象
const
sp<surfacecontrol>& surface = getSurfaceControl(env, clazz);
//得到源Surface所引用的SurfaceControl对象
const
sp<surfacecontrol>& rhs = getSurfaceControl(env, other);
//如果它们引用的不是同一个SurfaceControl对象
if
(!SurfaceControl::isSameSurface(surface, rhs)) {
setSurfaceControl(env, clazz, rhs);
}
}
</surfacecontrol></surfacecontrol>
2号Surface引用到了3号Surface的SurfaceControl对象后,通过writeToParcel()函数写会到应用程序进程。
frameworks\base\core\jni\ android_view_Surface.cpp
static
void
Surface_writeToParcel(
JNIEnv* env, jobject clazz, jobject argParcel, jint flags)
{
Parcel* parcel = (Parcel*)env->GetIntField(
argParcel, no.native_parcel);
if
(parcel == NULL) {
doThrowNPE(env);
return
;
}
const
sp<surfacecontrol>& control(getSurfaceControl(env, clazz));
if
(control != NULL) {
SurfaceControl::writeSurfaceToParcel(control, parcel);
}
else
{
sp<surface> surface(Surface_getSurface(env, clazz));
if
(surface != NULL) {
Surface::writeToParcel(surface, parcel);
}
else
{
SurfaceControl::writeSurfaceToParcel(NULL, parcel);
}
}
if
(flags & PARCELABLE_WRITE_RETURN_VALUE) {
setSurfaceControl(env, clazz, NULL);
setSurface(env, clazz, NULL);
}
}
</surface></surfacecontrol>
由于2号Surface引用的SurfaceControl对象不为空,因此这里就将SurfaceControl对象写会给应用程序进程
frameworks\native\libs\gui\ Surface.cpp
status_t SurfaceControl::writeSurfaceToParcel(
const
sp<surfacecontrol>& control, Parcel* parcel)
{
sp<isurface> sur;
uint32_t identity =
0
;
if
(SurfaceControl::isValid(control)) {
sur = control->mSurface;
identity = control->mIdentity;
}
parcel->writeStrongBinder(sur!=
0
? sur->asBinder() : NULL);
parcel->writeStrongBinder(NULL);
// NULL ISurfaceTexture in this case.
parcel->writeInt32(identity);
return
NO_ERROR;
}
</isurface></surfacecontrol>
写入Parcel包裹的对象顺序如下:
应用程序进程中的1号Surface通过readFromParcel()函数读取从WMS服务进程写回的Binder对象。
frameworks\base\core\jni\ android_view_Surface.cpp
static
void
Surface_readFromParcel(
JNIEnv* env, jobject clazz, jobject argParcel)
{
Parcel* parcel = (Parcel*)env->GetIntField( argParcel, no.native_parcel);
if
(parcel == NULL) {
doThrowNPE(env);
return
;
}
sp<surface> sur(Surface::readFromParcel(*parcel));
setSurface(env, clazz, sur);
}
</surface>
frameworks\native\libs\gui\ Surface.cpp
sp<surface> Surface::readFromParcel(
const
Parcel& data) {
Mutex::Autolock _l(sCachedSurfacesLock);
sp<ibinder> binder(data.readStrongBinder());
sp<surface> surface = sCachedSurfaces.valueFor(binder).promote();
if
(surface ==
0
) {
surface =
new
Surface(data, binder);
sCachedSurfaces.add(binder, surface);
}
else
{
// The Surface was found in the cache, but we still should clear any
// remaining data from the parcel.
data.readStrongBinder();
// ISurfaceTexture
data.readInt32();
// identity
}
if
(surface->mSurface == NULL && surface->getISurfaceTexture() == NULL) {
surface =
0
;
}
cleanCachedSurfacesLocked();
return
surface;
}
</surface></ibinder></surface>
应用程序进程中的1号Surface按相反顺序读取WMS服务端返回过来的Binder对象等数据,并构造一个native层的Surface对象。
Surface::Surface(
const
Parcel& parcel,
const
sp<ibinder>& ref)
: SurfaceTextureClient()
{
mSurface = interface_cast<isurface>(ref);
sp<ibinder> st_binder(parcel.readStrongBinder());
sp<isurfacetexture> st;
if
(st_binder != NULL) {
st = interface_cast<isurfacetexture>(st_binder);
}
else
if
(mSurface != NULL) {
st = mSurface->getSurfaceTexture();
}
mIdentity = parcel.readInt32();
init(st);
}
</isurfacetexture></isurfacetexture></ibinder></isurface></ibinder>
每个Activity可以有一个或多个Surface,默认情况下一个Activity只有一个Surface,当Activity中使用SurfaceView时,就存在多个Surface。Activity默认surface是在relayoutWindow过程中由WMS服务创建的,然后回传给应用程序进程,我们知道一个Surface其实就是应用程序端的本地窗口,关于Surface的初始化过程这里就不在介绍。
- Android应用程序窗口设计框架三
- Android应用程序窗口设计框架介绍
- Android应用程序窗口设计框架 一
- Android应用程序窗口设计框架二
- Android应用程序窗口设计框架四
- Android应用程序窗口设计框架介绍
- Android 应用程序框架设计
- 应用程序框架设计(2):SW系统的窗口类
- 应用程序框架设计(2):SW系统的窗口类
- 应用程序框架设计(2):SW系统的窗口类
- 应用程序框架设计(2):SW系统的窗口类
- 应用程序框架设计(2):SW系统的窗口类
- 应用程序框架设计(2):SW系统的窗口类
- 应用程序框架设计(2):SW系统的窗口类
- android应用程序窗口框架学习(4)-从setcontentview说起
- 应用程序主窗口-主窗口框架
- Android应用程序窗口
- 转:应用程序框架设计
- linux shell脚本速记
- Wince the global default build tree winceroot 问题
- Java标记接口
- Java Map集合利用比较器Comparator根据Key和Value的排序
- ubuntu hbase-0.98 配置(伪分布式)
- Android应用程序窗口设计框架三
- LS,MMSE,LMMSE,ML,MAP,LMS,AR,MSE误差介绍
- Oracle 获取某个日期为星期几的方法(不积跬步,无以至千里)
- 被管理员和谐了的最高票答案“知乎数据抓取程序”(.net、c#数据挖掘)
- 母牛生娃
- malloc与free机制探索
- java中实现指定位数“0000”,缺失部分用0补充
- C#进程注入
- Android应用程序窗口设计框架四