Activity的创建(从Activity的角度理解IWindowSession)

来源:互联网 发布:外链网盘系统源码 编辑:程序博客网 时间:2024/06/05 22:38
前言 
    本篇主要讲从Activity的角度来理解Window、DecorView、WindowManager、IWindowSession,以及ViewRootImpl与IWindowSession的关系。转载请注明来源,小石头的博客: http://blog.csdn.net/lu1024188315

1 创建Activity

     我们知道App进程的入口函数是ActivityThread中的main()函数,ActivityThread中有个函数handleLaunchActivity,Activity就是在这个函数中启动的,那么接下来我们看看
ActivityThread#handleLaunchActivity源码:
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {         ......        //函数1 返回一个Activity 实例        Activity a = performLaunchActivity(r, customIntent);        if (a != null) {            r.createdConfig = new Configuration(mConfiguration);            reportSizeConfigurations(r);            Bundle oldState = r.state;            //函数2 调用handleResumeActivity            handleResumeActivity(r.token, false, r.isForward,                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);            if (!r.activity.mFinished && r.startsNotResumed) {                performPauseActivityIfNeeded(r, reason);                 if (r.isPreHoneycomb()) {                    r.state = oldState;                }            }        } else {            // If there was an error, for any reason, tell the activity manager to stop us.            try {                ActivityManagerNative.getDefault()                    .finishActivity(r.token, Activity.RESULT_CANCELED, null,                            Activity.DONT_FINISH_TASK_WITH_ACTIVITY);            } catch (RemoteException ex) {                throw ex.rethrowFromSystemServer();            }        }    }
     接下来将对两个至关重要的1、2函数进行分析。

(1)函数1 :ActivityThread#performLaunchActivity源码:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {        // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")");        //aInfo 中存放了Activity、receiver节点信息        ActivityInfo aInfo = r.activityInfo;        .........//完成一些准备工作        Activity activity = null;        try {            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();            //mInstrumentation为Instrumentation类型,该实例调用newActivity创建一个Activity实例,其内部使用到了反射机制           // 至于怎么创建的稍后来讲。            activity = mInstrumentation.newActivity(                    cl, component.getClassName(), r.intent);             .......        } catch (Exception e) {             .......        }        try {            Application app = r.packageInfo.makeApplication(false, mInstrumentation);            ......            if (activity != null) {                //创建上下文实例                Context appContext = createBaseContextForActivity(r, activity);                .......
                activity.attach(appContext, this, getInstrumentation(), r.token,<pre data-original-code="" private="" activity="" performlaunchactivity(activityclientrecord="" r,="" intent="" customintent{"="" data-snippet-id="ext.3078aa40e37abac54d2a81092277cc8d" data-snippet-saved="false" data-codota-status="done" style="font-family: Monaco, Consolas, Courier, 'Lucida Console', monospace; line-height: 16px; white-space: pre-wrap; background-color: whitesmoke;">                        r.ident, app, r.intent, r.activityInfo, title, r.parent,                        r.embeddedID, r.lastNonConfigurationInstances, config,                        r.referrer, r.voiceInteractor, window);
.......
//调用Activity中的onCreate方法if (r.isPersistable()) { mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); }else { mInstrumentation.callActivityOnCreate(activity, r.state); } ....... }catch (SuperNotCalledException e) {throw e; }catch (Exception e) { ....... }return activity;}
 从上述代码不难看出,performLaunchActivity有三个主要的作用:
a:通过反射创建Activity实例
b:调用Activity的onCreate方法,而在Activity#onCreate方法中通过调用setContentVIew来设置UI元素。
c:Activity#attach方法,在这个方法中初始化了mWindow。

(2)函数2:ActivityThread#handleResumeActivity源码:

final void handleResumeActivity(IBinder token,            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {                    if (r.window == null && !a.mFinished && willBeVisible) {                //获取window对象                r.window = r.activity.getWindow();                 //获取View对象,这个View是最顶层的View                View decor = r.window.getDecorView();                decor.setVisibility(View.INVISIBLE);                 //获取ViewManager对象                ViewManager wm = a.getWindowManager();                WindowManager.LayoutParams l = r.window.getAttributes();                a.mDecor = decor;                l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;                l.softInputMode |= forwardBit;                if (r.mPreserveWindow) {                    a.mWindowAdded = true;                    r.mPreserveWindow = false;                    //获取ViewRootImpl对象 windowmanager通过它来操作view(window)                    // ViewRootImpl,在《window与windowmanager进阶篇1(ViewRootImpl深入理解)》已                          //经讲过                    ViewRootImpl impl = decor.getViewRootImpl();                    if (impl != null) {                        impl.notifyChildRebuilt();                    }                }                if (a.mVisibleFromClient && !a.mWindowAdded) {                    a.mWindowAdded = true;                    //把刚刚获取view放置到wm中                    wm.addView(decor, l);                }            } else if (!willBeVisible) {                r.hideForNow = true;            }               }

2 创建Window、DecorVIew、WindowManager

    下面我们考虑Activity如何和View、Window联系在一起?这个问题在《DecorView与window的创建》这篇已经讲过,在这里,我再来捋一遍,首先在Activity#onCreate方法中调用了setContentView,我们看下它的源码:

(1)创建Window、WindowManager

Activity#setContentView、getWindow:
public void setContentView(@LayoutRes int layoutResID) {     getWindow().setContentView(layoutResID);  //调用getWindow方法,返回mWindow     initWindowDecorActionBar();}...public Window getWindow() {        return mWindow;}
       方法Activity#getWindow返回Window类型,那么Window是什么鬼?看字义就是窗口呐,查看源码我们知道Window是个抽象类,在android 它的实现类是PhoneWindow,PhoneWindow存在于Activity中,它里面包括放置标题栏、DecorView等。了解更多参见《 WindowManger与window之基础篇》。
上面的mWindow又是在Activity#attach方法中初始化的,源码如下:
final void attach(Context context, ActivityThread aThread,            Instrumentation instr, IBinder token, int ident,            Application application, Intent intent, ActivityInfo info,            CharSequence title, Activity parent, String id,            NonConfigurationInstances lastNonConfigurationInstances,            Configuration config, String referrer, IVoiceInteractor voiceInteractor,            Window window) {        attachBaseContext(context);        mFragments.attachHost(null /*parent*/);        //初始化mWindow        mWindow = new PhoneWindow(this, window);        mWindow.setWindowControllerCallback(this);        mWindow.setCallback(this);        mWindow.setOnWindowDismissedCallback(this);        mWindow.getLayoutInflater().setPrivateFactory(this);        .....        mWindow.setWindowManager(                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),                mToken, mComponent.flattenToString(),                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);        if (mParent != null) {            mWindow.setContainer(mParent.getWindow());        }        mWindowManager = mWindow.getWindowManager();        mCurrentConfig = config;}
    看,初始化mWindow是通过new PhoneWindow(),已经明白了Window,下面我看看WindowManager,上面mWindow 调用了setWindowManager方法,其源码如下:
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,            boolean hardwareAccelerated) {        mAppToken = appToken;        mAppName = appName;        mHardwareAccelerated = hardwareAccelerated                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);        if (wm == null) {            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);        }        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);}
再看WindowManagerImpl#createLocalWindowManager源码:
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {        return new WindowManagerImpl(mContext, parentWindow);}
    在这里new了一个WindowManagerImpl赋值给了mWindowManager,其实WindowManagerImpl是WindowManager实现类,在这篇《WindowManger与window之基础篇》文章提到过,好吧,再把WindowManagerImpl源码贴过来:
public final class WindowManagerImpl implements WindowManager {    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();    private final Display mDisplay;    private final Window mParentWindow;    private IBinder mDefaultToken;    public WindowManagerImpl(Display display) {        this(display, null);    }    private WindowManagerImpl(Display display, Window parentWindow) {        mDisplay = display;        mParentWindow = parentWindow;    }    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {        return new WindowManagerImpl(mDisplay, parentWindow);    }    public WindowManagerImpl createPresentationWindowManager(Display display) {        return new WindowManagerImpl(display, mParentWindow);    }    ......}
好了,现在window、和windowManager都清楚了。

(2)创建DecorView

  Activity#setContentView——>PhoneWindow#setContentView,源码如下:
@Overridepublic void setContentView(int layoutResID) {        //mContentParent 初始值为null ,为ViewGroup类型,       //在绘制它的时候,会连他的的子类一起绘制。        if (mContentParent == null) {            //在这个方法中创建DecorView            installDecor();        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {            mContentParent.removeAllViews();        }        if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {            final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,                    getContext());            transitionTo(newScene);        } else {            //加载ID为layoutResID的布局            mLayoutInflater.inflate(layoutResID, mContentParent);        }      ......}
继续来看PhoneWindow#installDecor:
private void installDecor() {        mForceDecorInstall = false;        if (mDecor == null) {            // 1 mDecor 初始值为null,为Decor类型            mDecor = generateDecor(-1);            ......        } else {            mDecor.setWindow(this);        }        if (mContentParent == null) {           //2 若mContentParent为null,初始化mContentParent            mContentParent = generateLayout(mDecor);            ......            } else {               //创建标题栏                mTitleView = (TextView) findViewById(R.id.title);                if (mTitleView != null) {                    if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {                        final View titleContainer = findViewById(R.id.title_container);                        if (titleContainer != null) {                            titleContainer.setVisibility(View.GONE);                        } else {                            mTitleView.setVisibility(View.GONE);                        }                        mContentParent.setForeground(null);                    } else {                        mTitleView.setText(mTitle);                    }                }            }           ......          }
这个方法有三个作用:
a:调用PhoneWindow#generateDecor初始化mDecor;
b:若mContentParent为null,则调用generateLayout初始化mContentParent;
c:创建标题栏,从而也证明了,标题栏是在Activity最顶级View(DecorView)里面的;
还有,注意这里面两个函数1、2 。
接下来,继续来看函数1:PhoneWindow#generateDecor
protected DecorView generateDecor(int featureId) {        // System process doesn't have application context and in that case we need to directly use        // the context we have. Otherwise we want the application context, so we don't cling to the        // activity.        Context context;        if (mUseDecorContext) {            Context applicationContext = getContext().getApplicationContext();            if (applicationContext == null) {                context = getContext();            } else {                context = new DecorContext(applicationContext, getContext().getResources());                if (mTheme != -1) {                    context.setTheme(mTheme);                }            }        } else {            context = getContext();        }        return new DecorView(context, featureId, this, getAttributes());}
     好吧,到这里,小编已经晕头转向了,不知你如何,但是终于“柳暗花明又一村”了,已经出来了DecorView的构造方法,继续往下看DecorView到底是什么鬼?
public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {   ......}
    很明显DecorView继承了FrameLayout,说明它也是个ViewGroup。
函数2:PhoneWindow#generateLayout:
protected ViewGroup generateLayout(DecorView decor) {        // Apply data from current theme.获取属性值        TypedArray a = getWindowStyle();        ......//对属性值进行处理        //根据不同情况取得不同的标题栏资源        int layoutResource;        int features = getLocalFeatures();        // System.out.println("Features: 0x" + Integer.toHexString(features));        if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {            layoutResource = R.layout.screen_swipe_dismiss;        } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {            ......        } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0                && (features & (1 << FEATURE_ACTION_BAR)) == 0) {            ......        } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {            ......        } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {            ......        } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {            layoutResource = R.layout.screen_simple_overlay_action_mode;        } else {            // Embedded, so no decoration is needed.            layoutResource = R.layout.screen_simple;            // System.out.println("Simple!");        }        mDecor.startChanging();        //调用该方法把标题栏加载到mDecor上        mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);       ......        mDecor.finishChanging();        return contentParent;}
DecorView#onResourcesLoaded :
void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {        mStackId = getStackId();        ......        mDecorCaptionView = createDecorCaptionView(inflater);        final View root = inflater.inflate(layoutResource, null);        if (mDecorCaptionView != null) {            if (mDecorCaptionView.getParent() == null) {                addView(mDecorCaptionView,                        new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));            }            mDecorCaptionView.addView(root,                    new ViewGroup.MarginLayoutParams(MATCH_PARENT, MATCH_PARENT));        } else {            // Put it below the color views.            addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));        }        mContentRoot = (ViewGroup) root;        initializeElevation();    }
上面的addView是把标题栏添加到DecorView,好,到这里DecorView的工作总算完成了。
(3)findViewId的本质
   大家都知道findViewId是用来查找View,那么它的本质又是什么?那么就要看看它的源码咯,因为window是最顶级的窗口,那么我们直接到window查看其源码:
Window#findViewId:
@Nullablepublic View findViewById(@IdRes int id) {        return getDecorView().findViewById(id);}
没错,直接在DecorView中进行查找的,不用怀疑,因为DecorVIew是Window中最顶级View。这次明白findViewId到底是怎么的一回事了吧。

Window与View区别

    在前面的文章中多次提到过Window、DecorView与View,那么它们有什么区别?例如上面的在启动一个Activity的时候,随便初始化PhoneWindow,然后再添加View。
     View:是一个基本的UI元素,占据屏幕一块区域,用于绘制,并能处理事件。
     Window:是个抽象类, 它的实现类是PhoneWindow,是最顶级窗口,控制最顶级窗口的外观和行为,用来绘制背景、标题栏、DecorView、默认按键处理等。
针对它们的关系我作个了图,如下:

4 Surface

      回到方法ActivityThread#handleResumeActivity,在这个方法中WindowManager(其实现类WindowManagerImpl)的实例wm调用了addView()的方法,在WindowManagerImpl#addView又调用了
WindowManagerGlobal#addView,这个过程的源码分析在《window与windowManger之基础篇》中有,在这里就不累述了,WindowManagerGlobal#addView源码如下:
public void addView(View view, ViewGroup.LayoutParams params,            Display display, Window parentWindow) {        ............        synchronized (mLock) {            ............            root = new ViewRootImpl(view.getContext(), display);            view.setLayoutParams(wparams);            mViews.add(view);            mRoots.add(root);            mParams.add(wparams);        }        // do this last because it fires off messages to start doing things        try {            root.setView(view, wparams, panelParentView);        } catch (RuntimeException e) {            // BadTokenException or InvalidDisplayException, clean up.            synchronized (mLock) {                final int index = findViewLocked(view, false);                if (index >= 0) {                    removeViewLocked(index, true);                }            }            throw e;        }    }
     在这里引出了ViewRootImpl,在这篇文章《深入理解ViewRootImpl》中,我们知道ViewRootImpl继承ViewParent,它是整个控件树的根部,它是控件树正常运作的动力所在,控件的测量布局绘制以及输入事件的派发处理都由ViewRootImpl触发。那么ViewRootImpl的子View是绘制到哪里的?在这篇文章《深入理解ViewRootImpl》中介绍过ViewRootImpl中有个成员变量mSurface,它是Surface类型,来看下它的SDK说明,Handle onto a raw buffer that is being managed by the screen compositor.
有两个意思:
a:Surface 操作raw buffer(一块缓冲区域)
b:screen compositor(其实是SurfaceFlinger) 管理raw buffer
其实每个View都是在这块区域被绘制的。

IWindowSession

(1) 获取IWindowSession实例

ViewRootImpl#构造方法,源码如下:
public ViewRootImpl(Context context, Displaydisplay) {    /* 从WindowManagerGlobal中获取一个IWindowSession的实例。它是ViewRootImpl和      WMS进行通信的代理 */    mWindowSession= WindowManagerGlobal.getWindowSession(context.getMainLooper());    ......}
    说明,mWindowSession是WindowManagerGlobal调用getWindowSession方法初始化的,mWindowSession类型是IWindowSession,它是一个Binder对象,真正的实现类是Session
WindowManagerGlobal#getWindowSession源码如下:
@Overridepublic static IWindowSession getWindowSession() {        synchronized (WindowManagerGlobal.class) {            if (sWindowSession == null) {                try {                    InputMethodManager imm = InputMethodManager.getInstance();                    //获取WindowManagerService的Binder代理 windowManager                    IWindowManager windowManager = getWindowManagerService();                    //通过Binder代理 windowManager调用openSession函数                   //获取实例sWindowSession                    sWindowSession = windowManager.openSession(                            new IWindowSessionCallback.Stub() {                                @Override                                public void onAnimatorScaleChanged(float scale) {                                    ValueAnimator.setDurationScale(scale);                                }                            },                            imm.getClient(), imm.getInputContext());                } catch (RemoteException e) {                    throw e.rethrowFromSystemServer();                }            }            return sWindowSession;        }}
   说明,windowManager.openSession 是一个使用了Binder通信的跨进程调用,在这里先不讨论它(小弟也在研究它,有好的学习资源要分享出来啊!)。
IWindowManagerImpl#openSession,源码如下:
@Overridepublic IWindowSession openSession(IWindowSessionCallback argn1, IInputMethodClient arg0,            IInputContext arg1) throws RemoteException {        // TODO Auto-generated method stub        return null;}
IWindowManagerImpl,IWindowManager源码点击查看。

(2)IWindowSession 的 addToDisplay函数  

     再来看ViewRootImpl的函数setView,好吧,看过之前文章的,应该会注意到,已经无数次贴出这个函数,我想说:”我也很绝望,谁让它那么重要呢!“,还得继续来看:
ViewRootImpl#setView:
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {        synchronized (this) {            if (mView == null) {                mView = view;               ...........                try {                    mOrigWindowType = mWindowAttributes.type;                    mAttachInfo.mRecomputeGlobalAttributes = true;                    collectViewAttributes();                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,                            getHostVisibility(), mDisplay.getDisplayId(),                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,                            mAttachInfo.mOutsets, mInputChannel);                } catch (RemoteException e) {                   ...........                } finally {                    if (restore) {                        attrs.restore();                    }                }           ...........        }    }
说明,mWindow 是 WextendsIWindow.Stub 类型,W是ViewRootImpl的内部类。
Session#addToDisplay,源码如下:
final WindowManagerService mService;@Override  public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,          int viewVisibility, int displayId, Rect outContentInsets,          InputChannel outInputChannel) {      return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,              outContentInsets, outInputChannel);  } 
说明,这也是IPC的过程,即基于Binder通信的跨进程调用。从上面可以看出ViewRootImpl是通过IWindowSession和WindowManagerService进行交互的,在这里有两个IPC通信的过程:
a:通过远程调用openSession,获取IWindowSession实例
b:通过调用addToDisplay,mWindow attrs等参数传递给WindowManagerService。

(3)ViewRootImpl与WindowManagerService(WMS)的关系

如图:

说明:
a:ViewRootImpl通过IWindowSession与WMS进行交互,IWindowSession定义在IWindowSession.aidl文件中;
b:ViewRootImpl内部有个类W,它是基于Binder通信的类,它是IWindow的Bn端,用于响应请求,IWindow定义在IWindow.aidl文件中。










原创粉丝点击