Window和WindowManager(二)

来源:互联网 发布:用navicat连接mysql 编辑:程序博客网 时间:2024/06/02 22:59

接着上一节,View是Android中的视图的具体呈现方式,但是View必须依附在Window上,不能单独存在,因此有View的地方就有Window,Android中可以提供视图的地方有这么几种,Activity、dialog、Toast、PopupWindow、menu等,我们来分析一下这些地方的window的具体创建过程。

  • Activity中Window的创建过程
    Activity启动的时候过程比较复杂,最终会有ActivityThread中的performLaunchActivity()来完成整个的启动过程,具体的细节这里不做分析,该方法内部会通过类加载器来创建Activity的具体实例,并调用attach方法来为其关联上下文环境变量,代码如下:

    java.lang.ClassLoader cl = r.packageInfo.getClassLoader();activity = mInstrumentation.newActivity(cl,component.getClassName(),r.intent);...if(activity!=null){    Context appContext = createBaseContextForActivity(r,activity);    CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());    Configration config = new Configuration(mCompatConfiguration);    if(DEBUG_CONFIGURATION) Slog.v(TAG,"Launching activity"+r.activityInfo.name+"with config"+config);    activty.attch(appContext,this,getInstrumentation(),r.token,r.ident,app,r.intent,r.activityInfo,title,r.parent,r.embeddedID,r.lastNonConfiguraionInstances,config,r.voiceInteractor);    ...

    在Activity的attach方法里,系统会创建Activity所属的Window对象并为其设置回调接口,Window对象的创建是通过PolicyManager的makeNewWindow方法来实现的,由于Activity实现了Window 的callback接口,所以当Window接受到外界的状态改变的时候可以回调Activity的方法,Callback的方法很多,其中onAttachedToWindow、onDetachedFromWindow、dispatchTouchEvent等几个方法是我们比较熟悉的。

    mWindow = PolicyManager.makeNewWindow(this);mWindow.setCallback(this);mWindow.setOnWindowDismissedCallback(this);mWindow.getLayoutInflater().setPrivateFactory(this);if(info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED){    mWindow.setSoftInputMode(info.softInputMode);}if(info.uiOptions !=0){    mWindow.setUiOptions(info.uiOptions);}

    从上边的代码我们可以分析出来,Activity的Window是通过PolicyManger的一个工厂方法来创建的,在实际的调用中,PolicyManger的真正实现类是Policy类,该类实现了Ipolicy接口,Policy类中的makeNewWindow方法的实现如下:

    public Window makeNewWindow(Context context){    return new PhoneWindow(context);}

    由此,我们可以确定Window的具体实现类是PhoneWindow。到这里,Window已经创建完毕了,但是我们的视图还没有附加上去,要分析视图的附件过程,我们通过Activity的setContentview方法入手即可:

    public void setContetView(int layoutResID){    getWindow().setContentView(layoutResID);    initWindowDecorActionBar();}

    这里我们可以看出,Activity中setcontentview的具体实现交给了window,而Window的具体实现是phoneWindow,所以我们来看一下PhoneWindow的setContentview方法,PhoneWindow中的实现过程也是比较复杂的,我们看其中几个关键步骤,

    1. 如果没有DecorView,创建DecorView

      DecorView是Activity中的顶级View,是一个FrameLayout,包括标题栏和内容栏,我们在activity中的setcontentview设置的就是decorView中的内容栏。

      DecorView的创建过程由installDecor来完成,该方法内部会调用generateDecor方法来创建一个空表的DecorView。

      而后,PhoneWindow通过generateLayout方法来加载具体的布局文件到DecorView中。

    2. 将View添加到DecorView中的content部分

    3. 回调Activity的onContentChanged方法来通知Activity视图已经改变,该方法在Activity中是一个空实现,需要的时候我们可以在自己的Activity中去处理这个回调。

    经过上边几个步骤,DecorView已经被创建并初始化完成,Activity中的布局文件也已经添加到了DecorView中的mContentParent部分,但是这时候DecorView还没有被WindowManger正式的添加到Window中,在ActivityThread中的handleResumeActivity方法执行之后,DecorView才算是真正的完成了添加和显示这两个过程,Activity的视图才能被用户看到,在该方法中主要执行了两个步骤,首先他会调用activity的onResume方法,接着调用activity的makeVisible方法,实现如下:

    void makeVisible(){    if(!mWindowAdded){        ViewManager wm = getWindowManager();        wm.addView(mDecor,getWindow().getAttributes());        mWindowAdded = true;    }    mDecor.setVisibility(View.VISIBLE);}

到这里,Activity的Window创建过程已经分析完毕。

  • dialog的window创建过程
    dialog的window创建过程与activity基本类似,也是由以下几个步骤来完成的

    1. 创建window
    2. 初始化DecorView并将dialog视图添加到DecorView中
    3. 将DecorView添加到window中并显示

    但需要注意的是,普通的dialog需要用activity的context来创建,如果使用application的context,会报错。
    如果我们确实需要使用application的context来创建dialog的话,那么我们可以将dialog的window设置为系统级别,同时添加对应权限即可。

    dialog.getWindow().setType(LayoutParams.TYPE_SYSTEM_ERROR);

    同时在manifest中添加系统Window的权限:

    < uses-permission android:name=”android.permission.SYSTEM_ALLERT_WINDOW”/ >

参考资料:Android开发艺术探索

0 0