应用窗口的从创建到显示的过程
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架构不了解的可以去看看)这样,应用窗口的创建和显示工作基本完成了。可以归纳为以上四大步。
相关文章推荐
- Introduction to Engine user guide(介绍Docker引擎手册)
- 蘑菇阵
- 输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不改变
- C++封装继承多态总结(转)
- Shell脚本实现文件的互斥访问
- C# WinForm 技巧:COMBOBOX搜索提示
- 看门狗定时器的编程实践
- MVC通过扩展HtmlHelper实现CheckBoxList
- 快速排序及其优化
- Oracle 函数
- Word排版时同时插入脚注和分栏的技巧总结
- 阿里云OSS 上传文件
- 从网络获取json后实现新闻列表界面
- 【Android】软件界面全屏显示
- 计算机图形学(一) 视频显示设备_6_三维观察设备
- lightoj 1301 - Monitoring Processes 贪心
- c语言实现输出一个数的每一位
- shell之正则
- 本地配置环境打开项目出现404/本地wampserver配置伪静态以及php.ini配置
- 导入数据到HBase的方式选择