应用窗口的从创建到显示的过程

    


        首先了解一下安卓系统窗口的类型,系统定义了三种窗口类型,包括:

                1.应用窗口。这类窗口一般一个Activity对应一个应用窗口。

                2.子窗口。这种类型的窗口必须要有一个父窗口,如PopupWindow即属于这类窗口。

                3.系统窗口。如Toast即属于这类窗口。


   每一类窗口都有一代表其层次的常量,一般这个常量越大表示层的位置越靠上,可以知道 系统窗口这个常量最大,子窗口次之,应用窗口最小。


   接下来说一下应用窗口的整个创建过程,归纳一下可以分为一下几大步:


   1.首先创建一个Activity并且配置这个Activity。由于一个应用窗口一般对应一个Activity,所以创建应用窗口之前我们需要首先创建一个Activity.

      先利用ClassLoader从程序文件中装载指定的Activity对应的Class文件,如下:

     

    Activity activity = null;  
        try {  
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();  
            activity = mInstrumentation.newActivity(  
                    cl, component.getClassName(), r.intent);  
            ......  
        } catch (Exception e) {  
            ......  
        }  

       然后构造好这个Activity后调用attach()函数来设置内部变量,并创建一个Window对象,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,  
            Object lastNonConfigurationInstance,  
            HashMap<String,Object> lastNonConfigurationChildInstances,  
            Configuration config) {  
        attachBaseContext(context);  
  
        mWindow = PolicyManager.makeNewWindow(this);  //为这个Activity创建一个Window对象
        mWindow.setCallback(this);  //设置该window的Callback接口为当前的Activity对象
 
    
       2. 配置Window对象。上面第一步已经创建并配置好Activity,并且为Activity创建了一个Window对象,接下来就是配置这个Window对象。

          我们知道每个Window内部都有一个WindowManager对象,所以我们需要给Window内部的mWindowManager变量赋值,如下:

       mWindowManager=mWindow.getWindowManager();



      3.给窗口添加View.配置好Activity和Window后,我们就要给这个Window加上View了。在PerformLaunchActivity()内部调用callActivityOnCreate()开始,并最终会调用到Activity的onCreate()函数,我们知道onCreate()函数里面有一个setContentView(),我们平常一般通过这个函数来设置Activity的View,其实这个setContentView内部是调用到其对应的Window对象的setContentView()函数

    

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

  然后我们就来看看Window对象的setContentView()内部做了些什么:

  

@Override  
   public void setContentView(int layoutResID) {  
       if (mContentParent == null) {  
           installDecor();  
       } else {  
           mContentParent.removeAllViews();  
       }  
       mLayoutInflater.inflate(layoutResID, mContentParent);  
       final Callback cb = getCallback();  
       if (cb != null && !isDestroyed()) {  
           cb.onContentChanged();  
       }  
   }  
   

    首先是installDecor()为Window安装一个窗口修饰,关于窗口修饰,其实就是一个基础窗口,比如标题栏(ActionBar),我们知道Actionbar有很多不同的主题,所以也就是这个窗口修饰有很多不同主题,一般来说一个窗口修饰就是为我们创建一个标题栏(当然也有不要标题栏的主题),然后下面一个空的FrameLayout,之后我们定义的Layout.xml就是放在这个FrameLayout里面,称之为窗口内容。

    然后通过inflate()方法来把我们的layout.xml添加到窗口修饰中,当做窗口内容。

    最后这个cb即所在的Activity(前面activity的attach()方法里设置了Window的回调),cb.onContentChanged()通知应用程序窗口内容发生了改变,这种回调实现了Window里的内容发生了改变,可以调用Activity里的方法来处理这种改变,也就是起到通知Activity的作用。



       4.Window的视图配置完后,就是把创建窗口告知Wms(WindowManagerService),Wms负责把窗口显示在屏幕上

         当Activity各方面都准备好后,就通知Ams(ActivityManagerService),Ams负责Activity的管理,当Ams确定Activity都准备好没问题后,一样的会通过IPC跨进程的方式调到客户端IBinder对象ApplicationThread,ApplicationThread中通过Hander发消息到主线程ActivityThread中调用handleResumeActivity()中调用Activity的onResume()方法,然后在其中再调用makeVisiable(),最后makeVisiable()就会调用WindowManger的addView()来让View和Window建立联系:

        

void makeVisible() {    
    if (!mWindowAdded) {    
        ViewManager wm = getWindowManager();   // 获取WindowManager对象    
        wm.addView(mDecor, getWindow().getAttributes());    
        mWindowAdded = true;    
    }    
    mDecor.setVisibility(View.VISIBLE); //显示  
}    

从上面可以看出先获取WindowManager对象,然后wm.addView()添加窗口,然后显示。


  那么这个addView()里面做了些什么呢?


  ①首先创建一个ViewRoot对象(每个窗口都有一个ViewRoot对象(实现类ViewRootImpl),因为Window的添加显示经常要与Wms打交道,即进程间通信,必然要用到IPC调用,所以ViewRoot必不可少[ViewRoot里有个ViewRootHandler,可以完成线程间通信,而ViewRoot内部又有Binder子类W类,可以完成进程间通信])

  

 ②调用ViewRoot的setView()方法完成添加工作。

         setView()方法有三个参数,分别是:1.View即要显示的整个界面   2.LayoutParams窗口的参数,如大小位置等 3.panelParentView

        setView()里做的事:

        1.给重要变量赋值

         2.调用requestLayout().发出界面重绘请求,这个方法只是给UI线程发一个异步消息,通知它下一个消息处理是界面重绘,从而让该窗口在相应任何其他用户消息之前首先变得可见。

         3.调用sWindowSession.add().这一步也是重中之重,这一步实现了跨进程把窗口添加到Wms中。这个sWindowSession对象是Viewroot中的一个Binder引用,即对应Wms上的一个Session对象,这样就可以在ViewRoot里调用Wms上的方法add()来实现添加窗口了。(关于Binder架构不了解的可以去看看)




          这样,应用窗口的创建和显示工作基本完成了。可以归纳为以上四大步。

   

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值