简述Activity的启动流程(界面显示)
2016-05-13 17:55
387 查看
写完上一篇博客之后,花时间看了一下Binder,还是只能看个皮毛,所以,在自己没有完全掌握的情况的,我会更注重这种上层的宏观流程,而不纠结于底层细节。
我们自己写的布局是在setContentView()中开始执行的,大致流程就是,系统会根据主题什么的创建出一个最外层的ViewGroup,然后把我们的View添加进去,然后通知WmS添加ViewGroup,界面就这么出来了。
Activity的attach()方法
mWindow是一个PhoneWindow对象,该Window和Activity进行了绑定。
PhoneWindow
DecorView是一个最外层布局,看一看generateLayout()方法
in就是系统根据主题什么的创建出来的一个外层布局,并且给了我们一个id为
ID_ANDROID_CONTENT的父布局,我们将自己给Activity设置的View就添加到这个父布局中。
此时,我们已经将本地工作准备完毕,接着就是告知WmS将这个ViewGroup显示出来。
当我们向系统发出启动Activity的消息之后,系统经过处理之后也会回发一个消息给我们,这个消息被ApplicationThread接收,然后发一个handler消息给ActivityThread,然后执行handleLaunchActivity()
我们都知道,Activity的onResume()方法执行表示界面已经显示出来了
handleResumeActivity()方法
在这个方法中就是请求WmS将View添加进去。
wm.addView最终执行的是WindowManagerGlobal(全局唯一)
ViewRootImpl的setView()方法
这里的mWindow是一个W类,也是ViewRootImpl的内部类,当WmS那边添加完窗口后,会反馈一个消息,这个消息由W类接受,然后W类发送一个Handler消息给ViewRootImpl。
说到这里,有必要理清一下WindowManger,到底有几个,我们拿到的是哪个,举个例子吧,Toast与Activity是无关的吧,原因就在WindowManager身上。
先看看Activity是怎么拿的吧
返回的是与他绑定的Window的WindowManager.
ActivityThread的performLaunchActivity()方法:
再看Activity的attach()方法
ContextImpl有一段静态代码块
一旦执行注册,就放到缓存中了,下次你请求拿的时候就是从缓存队列中拿到的,所以,他们是全局唯一的。我们通过Activity的getSystemService()拿到的就是这里的WindowManager.
再回到Activity的onAttach()方法中的那个setWindowManager()方法
注意:在注册服务的代码中,这个parentWindow==null.
我们自己写的布局是在setContentView()中开始执行的,大致流程就是,系统会根据主题什么的创建出一个最外层的ViewGroup,然后把我们的View添加进去,然后通知WmS添加ViewGroup,界面就这么出来了。
Activity的attach()方法
mWindow = PolicyManager.makeNewWindow(this);
mWindow是一个PhoneWindow对象,该Window和Activity进行了绑定。
PhoneWindow
@Override public void setContentView(View view, ViewGroup.LayoutParams params) { ...... if (mContentParent == null) { installDecor(); } else { mContentParent.removeAllViews(); } mContentParent.addView(view, params); ......
DecorView是一个最外层布局,看一看generateLayout()方法
...... View in = mLayoutInflater.inflate(layoutResource, null); decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); ......
in就是系统根据主题什么的创建出来的一个外层布局,并且给了我们一个id为
ID_ANDROID_CONTENT的父布局,我们将自己给Activity设置的View就添加到这个父布局中。
此时,我们已经将本地工作准备完毕,接着就是告知WmS将这个ViewGroup显示出来。
当我们向系统发出启动Activity的消息之后,系统经过处理之后也会回发一个消息给我们,这个消息被ApplicationThread接收,然后发一个handler消息给ActivityThread,然后执行handleLaunchActivity()
....... Activity a = performLaunchActivity(r, customIntent); if (a != null) { r.createdConfig = new Configuration(mConfiguration); Bundle oldState = r.state; handleResumeActivity(r.token, false, r.isForward, !r.activity.mFinished && !r.startsNotResumed); ......
我们都知道,Activity的onResume()方法执行表示界面已经显示出来了
handleResumeActivity()方法
if (r.activity.mVisibleFromClient) { r.activity.makeVisible(); }
void makeVisible() { if (!mWindowAdded) { ViewManager wm = getWindowManager(); wm.addView(mDecor, getWindow().getAttributes()); mWindowAdded = true; } mDecor.setVisibility(View.VISIBLE); }
在这个方法中就是请求WmS将View添加进去。
wm.addView最终执行的是WindowManagerGlobal(全局唯一)
root = new ViewRootImpl(view.getContext(), display); view.setLayoutParams(wparams); mViews.add(view); mRoots.add(root); mParams.add(wparams); } // do this last because it fires off messages to start doing things try { //这个方法很重要 root.setView(view, wparams, panelParentView);
ViewRootImpl的setView()方法
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mInputChannel);
这里的mWindow是一个W类,也是ViewRootImpl的内部类,当WmS那边添加完窗口后,会反馈一个消息,这个消息由W类接受,然后W类发送一个Handler消息给ViewRootImpl。
说到这里,有必要理清一下WindowManger,到底有几个,我们拿到的是哪个,举个例子吧,Toast与Activity是无关的吧,原因就在WindowManager身上。
先看看Activity是怎么拿的吧
@Override public Object getSystemService(String name) { ...... if (WINDOW_SERVICE.equals(name)) { return mWindowManager; } else if (SEARCH_SERVICE.equals(name)) { ensureSearchManager(); return mSearchManager; } return super.getSystemService(name); }
返回的是与他绑定的Window的WindowManager.
ActivityThread的performLaunchActivity()方法:
//此时Activity对象已经创建出来 ...... if (activity != null) { //为Activity创建一个ContextImpl对象 Context appContext = createBaseContextForActivity(r, activity); //配置Activity内部的参数 activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config);
再看Activity的attach()方法
mWindow.setWindowManager( (WindowManager)context.getSystemService(Context.WINDOW_SERVICE), mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
ContextImpl有一段静态代码块
static { ...... //这里有一堆类似的XXX_SERVICE的注册 ...... registerService(WINDOW_SERVICE, new ServiceFetcher() { Display mDefaultDisplay; public Object getService(ContextImpl ctx) { //搞一个Display实例 Display display = ctx.mDisplay; if (display == null) { if (mDefaultDisplay == null) { DisplayManager dm = (DisplayManager)ctx.getOuterContext(). getSystemService(Context.DISPLAY_SERVICE); mDefaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY); } display = mDefaultDisplay; } //返回一个WindowManagerImpl实例 return new WindowManagerImpl(display); }}); ...... }
一旦执行注册,就放到缓存中了,下次你请求拿的时候就是从缓存队列中拿到的,所以,他们是全局唯一的。我们通过Activity的getSystemService()拿到的就是这里的WindowManager.
再回到Activity的onAttach()方法中的那个setWindowManager()方法
public void setWindowManager(WindowManager wm, IBinder appToken, String appName, boolean hardwareAccelerated) { if (wm == null) { wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE); } //通过全局的WindowManager创建一个本地的(属于Activity) //的localWindowManager mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this); }
public WindowManagerImpl createLocalWindowManager(Window parentWindow) { //这个parentWindow就是与Activity绑定的Window return new WindowManagerImpl(mDisplay, parentWindow); }
注意:在注册服务的代码中,这个parentWindow==null.
相关文章推荐
- ML2 Extension Manager
- hdu 4044 GeoDefense 树形DP+分组背包
- Java语言如何进行异常处理,关键字:throws、throw、try、catch、finally分别如何使用?
- cydiaSubstrate hook java/native 研究记录
- 高斯模糊算法
- System类及其getProterties( )和getProperty( )
- 概率图模型(一):贝叶斯网络
- React.js中的表单
- 揭秘LOGO设计流程!超详细的腾讯云LOGO 改版记录全过程
- IIS配置网站出现404
- 根据字体多少使UILabel自动调节尺寸
- 解释 int num = 5;(面试)
- 浙大 PAT Advanced level 1014. Waiting in Line (30)
- ToString()、Convert.ToString()、(string)、as string 的区别
- 列转行
- springmvc+mybatis框架搭建流程详解
- 关于Emacs终端下的Alt模拟Meta与全局菜单冲突的问题
- BZOJ 2160 拉拉队排练
- 这是对上一篇文件进行优化,加入了服务service
- iOS网络资源汇总之UI