Android应用程序窗口设计框架三

来源:互联网 发布:五笔练习软件 编辑:程序博客网 时间:2024/05/23 01:57

performTraversals函数相当复杂,其主要实现以下几个重要步骤:

1.执行窗口测量;

2.执行窗口注册;

3.执行窗口布局;

4.执行窗口绘图;

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
privatevoid performTraversals() {
    // cache mView since it is used so much below...
    finalView host = mView;
    if(host == null|| !mAdded)
        return;
    mWillDrawSoon = true;
    booleanwindowSizeMayChange = false;
    booleannewSurface = false;
    booleansurfaceChanged = false;
    WindowManager.LayoutParams lp = mWindowAttributes;
    intdesiredWindowWidth;
    intdesiredWindowHeight;
    finalView.AttachInfo attachInfo = mAttachInfo;
    finalint viewVisibility = getHostVisibility();
    booleanviewVisibilityChanged = mViewVisibility != viewVisibility
            || mNewSurfaceNeeded;
    WindowManager.LayoutParams params = null;
    if(mWindowAttributesChanged) {
        mWindowAttributesChanged = false;
        surfaceChanged = true;
        params = lp;
    }
    ...
    /****************执行窗口测量******************/
    booleanlayoutRequested = 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{
            finalint surfaceGenerationId = mSurface.getGenerationId();
            relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
            ...
        }catch(RemoteException e) {
        }
        ...
        if(!mStopped) {
            booleanfocusChangedDueToTouchMode = 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);
                ...
            }
        }
    }
    /****************执行窗口布局******************/
    finalboolean didLayout = layoutRequested && !mStopped;
    booleantriggerGlobalLayoutListener = didLayout
            || attachInfo.mRecomputeGlobalAttributes;
    if(didLayout) {
        performLayout();
        ...
    }
    ...
    /****************查找窗口焦点******************/
    booleanskipDraw = 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;
        }
    }elseif (mWindowsAnimating) {
        skipDraw = true;
    }
    /****************执行窗口绘制******************/
    mFirst = false;
    mWillDrawSoon = false;
    mNewSurfaceNeeded = false;
    mViewVisibility = viewVisibility;
    ...
    booleancancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw() ||
            viewVisibility != View.VISIBLE;
    if(!cancelDraw && !newSurface) {
        if(!skipDraw || mReportNextDraw) {
            if(mPendingTransitions != null&& mPendingTransitions.size() > 0) {
                for(inti = 0; i < mPendingTransitions.size(); ++i) {
                    mPendingTransitions.get(i).startChangingAnimations();
                }
                mPendingTransitions.clear();
            }
            performDraw();
        }
    }else{
        if(viewVisibility == View.VISIBLE) {
            // Try again
            scheduleTraversals();
        }elseif (mPendingTransitions != null&& mPendingTransitions.size() > 0) {
            for(inti = 0; i < mPendingTransitions.size(); ++i) {
                mPendingTransitions.get(i).endChangingAnimations();
            }
            mPendingTransitions.clear();
        }
    }
}
performMeasure

frameworks\base\core\java\android\view\ViewRootImpl.java

?
1
2
3
4
5
6
7
8
privatevoid performMeasure(intchildWidthMeasureSpec, intchildHeightMeasureSpec) {
 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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
privateint relayoutWindow(WindowManager.LayoutParams params, intviewVisibility,
        booleaninsetsPending) throwsRemoteException {
    ...
    intrelayoutResult = 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);
    ...
    returnrelayoutResult;
}

这里通过前面获取的IWindowSession代理对象请求WMS服务执行窗口布局,mSurface是ViewRootImpl的成员变量

?
1
privatefinal Surface mSurface = newSurface();

frameworks\base\core\java\android\view\ Surface.java

?
1
2
3
4
5
6
7
publicSurface() {
    checkHeadless();
    if(DEBUG_RELEASE) {
        mCreationStack = newException();
    }
    mCanvas = newCompatibleCanvas();
}

该Surface构造函数仅仅创建了一个CompatibleCanvas对象,并没有对该Surface进程native层的初始化,到此我们知道应用程序进程为每个窗口对象都创建了一个Surface对象。并且将该Surface通过跨进程方式传输给WMS服务进程,我们知道,在Android系统中,如果一个对象需要在不同进程间传输,必须实现Parcelable接口,Surface类正好实现了Parcelable接口。ViewRootImpl通过IWindowSession接口请求WMS的完整过程如下:

frameworks\base\core\java\android\view\IWindowSession.java$ Proxy

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
publicint relayout(android.view.IWindow window, intseq,
        android.view.WindowManager.LayoutParams attrs, intrequestedWidth,
        intrequestedHeight, intviewVisibility, intflags,
        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) throwsandroid.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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
publicboolean onTransact(intcode, android.os.Parcel data,
        android.os.Parcel reply, intflags)throwsandroid.os.RemoteException {
    switch(code) {
    caseTRANSACTION_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 = newandroid.graphics.Rect();
        android.graphics.Rect _arg8;
        _arg8 = newandroid.graphics.Rect();
        android.graphics.Rect _arg9;
        _arg9 = newandroid.graphics.Rect();
        android.graphics.Rect _arg10;
        _arg10 = newandroid.graphics.Rect();
        android.content.res.Configuration _arg11;
        _arg11 = newandroid.content.res.Configuration();
        android.view.Surface _arg12;
        _arg12 = newandroid.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);
        }
        returntrue;
    }
    }
}

该函数可以看出,WMS服务在响应应用程序进程请求添加窗口时,首先在当前进程空间创建一个Surface对象,然后调用Session的relayout()函数进一步完成窗口添加过程,最后将WMS服务中创建的Surface返回给应用程序进程。
\
到目前为止,在应用程序进程和WMS服务进程分别创建了一个Surface对象,但是他们调用的都是Surface的无参构造函数,在该构造函数中并未真正初始化native层的Surface,那native层的Surface是在那里创建的呢?
frameworks\base\services\java\com\android\server\wm\ Session.java

?
1
2
3
4
5
6
7
8
9
10
publicint relayout(IWindow window, intseq, WindowManager.LayoutParams attrs,
        intrequestedWidth, intrequestedHeight, intviewFlags,
        intflags, Rect outFrame, Rect outContentInsets,
        Rect outVisibleInsets, Configuration outConfig, Surface outSurface) {
    intres = mService.relayoutWindow(this, window, seq, attrs,
            requestedWidth, requestedHeight, viewFlags, flags,
            outFrame, outContentInsets, outVisibleInsets,
            outConfig, outSurface);
    returnres;
}

frameworks\base\services\java\com\android\server\wm\ WindowManagerService.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
publicint relayoutWindow(Session session, IWindow client, intseq,
        WindowManager.LayoutParams attrs, intrequestedWidth,
        intrequestedHeight, intviewVisibility, intflags,
        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) {
            return0;
        }
        ...
        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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Surface createSurfaceLocked() {
    if(mSurface == null) {
        ...
        try{
            ...
            if(DEBUG_SURFACE_TRACE) {
                mSurface = newSurfaceTrace(
                        mSession.mSurfaceSession, mSession.mPid,
                        attrs.getTitle().toString(),
                        0, w, h, format, flags);
            }else{
                mSurface = newSurface(
                    mSession.mSurfaceSession, mSession.mPid,
                    attrs.getTitle().toString(),
                    0, w, h, format, flags);
            }
            mWin.mHasSurface = true;
        }catch(Surface.OutOfResourcesException e) {
            ...
        }
        Surface.openTransaction();
        ...
    }
    returnmSurface;
}

Surface创建过程
frameworks\base\core\java\android\view\Surface.java

?
1
2
3
4
5
6
7
8
9
10
publicSurface(SurfaceSession s,intpid, String name, intdisplay, intw, inth, intformat, intflags)
    throwsOutOfResourcesException {
    checkHeadless();
    if(DEBUG_RELEASE) {
        mCreationStack = newException();
    }
    mCanvas = newCompatibleCanvas();
    init(s,pid,name,display,w,h,format,flags);
    mName = name;
}

frameworks\base\core\jni\ android_view_Surface.cpp

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
staticvoid 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{
        constjchar* str = env->GetStringCritical(jname, 0);
        constString8 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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
staticvoid Surface_copyFrom(JNIEnv* env, jobject clazz, jobject other)
{
    if(clazz == other)
        return;
    if(other == NULL) {
        doThrowNPE(env);
        return;
    }
    //得到当前Surface所引用的SurfaceControl对象
    constsp<surfacecontrol>& surface = getSurfaceControl(env, clazz);
    //得到源Surface所引用的SurfaceControl对象
    constsp<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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
staticvoid 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;
    }
    constsp<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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
status_t SurfaceControl::writeSurfaceToParcel(
        constsp<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);
    returnNO_ERROR;
}
</isurface></surfacecontrol>

写入Parcel包裹的对象顺序如下:

\

应用程序进程中的1号Surface通过readFromParcel()函数读取从WMS服务进程写回的Binder对象。
frameworks\base\core\jni\ android_view_Surface.cpp

?
1
2
3
4
5
6
7
8
9
10
11
12
staticvoid 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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sp<surface> Surface::readFromParcel(constParcel& data) {
    Mutex::Autolock _l(sCachedSurfacesLock);
    sp<ibinder> binder(data.readStrongBinder());
    sp<surface> surface = sCachedSurfaces.valueFor(binder).promote();
    if(surface == 0) {
       surface = newSurface(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();
    returnsurface;
}
</surface></ibinder></surface>

应用程序进程中的1号Surface按相反顺序读取WMS服务端返回过来的Binder对象等数据,并构造一个native层的Surface对象。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Surface::Surface(constParcel& parcel, constsp<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);
    }elseif (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的初始化过程这里就不在介绍。


0 0
原创粉丝点击