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

前言 
    本篇主要讲从 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,源码如下:
@Override
public 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:
@Nullable
public 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源码如下:
@Override
public 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,源码如下:
   
   
@Override
public 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  是  W extends IWindow.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文件中。










  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值