您的位置:首页 > 其它

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

2016-04-12 10:56 246 查看
首先了解一下安卓系统窗口的类型,系统定义了三种窗口类型,包括: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()内部做了些什么:
@Overridepublic 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都准备好没问题后,会调用Activity的makeVisible()方法,从字面意思理解我们就知道,所以这个方法里面必定是让Window显示,把Window添加进Wms:
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对象,因为Window的添加显示经常要与Wms打交道,即进程间通信,必然要用到IPC调用,所以ViewRoot必不可少[ViewRoot本身是个Handler,可以完成线程间通信,而ViewRoot内部又有Binder子类,可以完成进程间通信])②调用ViewRoot的setView()方法完成添加工作。setView()方法有三个参数,分别是:1.View即要显示的整个界面 2.LayoutParams窗口的参数,如大小位置等 3.panelParentViewsetView()里做的事:1.给重要变量赋值2.调用requestLayout().发出界面重绘请求,这个方法只是给UI线程发一个异步消息,通知它下一个消息处理是界面重绘,从而让该窗口在相应任何其他用户消息之前首先变得可见。3.调用sWindowSession.add().这一步也是重中之重,这一步实现了跨进程把窗口添加到Wms中。这个sWindowSession对象是Viewroot中的一个Binder引用,即对应Wms上的一个Session对象,这样就可以在ViewRoot里调用Wms上的方法add()来实现添加窗口了。(关于Binder架构不了解的可以去看看)这样,应用窗口的创建和显示工作基本完成了。可以归纳为以上四大步。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: