概述
首先了解一下安卓系统窗口的类型,系统定义了三种窗口类型,包括:
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架构不了解的可以去看看)
这样,应用窗口的创建和显示工作基本完成了。可以归纳为以上四大步。
最后
以上就是体贴绿茶为你收集整理的应用窗口的从创建到显示的过程的全部内容,希望文章能够帮你解决应用窗口的从创建到显示的过程所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复