context具体实现是contextimpl,也就是application里attach时系统传入的basecontext,attach之后各种context的功能才会正常,context一共三种,application,activity,service,其它都不是context
vhbhn
vbbbb
这涉及APP启动过程,app由系统启动,系统通过桌面这个程序来启动对应的app,首先找到apk文件进行分析和收集,然后把apk信息传入来启动app,我们从ActivityThread的main方法开始看,这是入口方法,标准的java入口main方法,这里面会启动mainlooper,即将一个looper放到当前threadlocal(mainthread),在开启looper循环之前,实例化一个activitythread,这时候H类会在activitytread里被初始化,也就是为啥在准备mainlooper之后和启动mainlooper之间实例化activitythread(不然启动mainlooper后就进入死循环了,同一个线程里后面的代码就无法执行了,所以启动mainlooper必须最后执行),然后调用activitythread的attach方法,这个方法是后续流程的开始,然后启动looper循环后,main方法就结束了
这里插一段looper说明,looper在主线程中启动之后就进入死循环,这里有两个问题,一,进入死循环后如何执行其它任务,二,死循环会不会消耗CPU资源,答案是同一个原理,即系统的epoll多路复用,大概跟nio一样,looper死循环一个是为了让主线程不退出,必须不能结束啊,它等待消息队列中的消息,来一个处理一个,等待的是多进程通信搞过来的消息,比如屏幕刷新view重绘,点击事件等,底层来看就是接收系统的叫醒,阻塞的时候是epoll闲置状态,等有事件了,在通过epoll叫醒,使用JAVA锁机制也可以实现,估计效率低?消息队列就是生产者消费者,主线程消费,其它线程生产,如果消息队列是主线程和其它线程共享的(looper放到了threadlocal就是不共享呗),那用JAVA的阻塞队列也可以吧,epoll waite换成lock的await
attach方法是个厉害的家伙,如果系统进程走到这,instrument类,contextImpl类,都在这new,如果是用户进程,就启用进程间通信机制,即applicationthread关联上activitymanager,用户进程是客户端,activitymanager是服务端,applicationtread是客户端驻服务端代表,服务端通过它跟客户端交互,这都走binder机制
说回application创建,我们断点到application的attachbasecontext方法,发现我们的H收到一个bindapplication的进程间调用,系统让我们绑定一个application,不晓得这是不是attach时applicationthread关联上之后的第一个事件,但对于我们的应用肯定是非常靠前的事件了,就从它开始往下说
handlebindapplication,主要应该是启动一个application,并把系统收集的apk资料绑定到application里,进程名啊,是不是24小时制啊,设备标识,debug设置,new一个instrumentioninfo,然后到了我们关注的,new一个contextImpl,设置一些什么设备图形支持,不管,然后再new一个ctxl,用来用反射new一个instrumention,虽然instrumention也很厉害,先不管,接着调用loadedapk的makeapplication,这个是要关心的,这个方法里,再new一个ctxl,再调用instrumention的newapplication方法,得到我们APP的application对象,同时调用application的attach方法,传入最后new的这个ctxl,即是basecontext,可见application和basecontext不是同一个对象,getbasecontext在这之后就会有值了,但是getapplicationcontext是没值的,这个函数会返回loadedapk的mapplication属性,而在attachbasecontext函数结束后这个属性才赋值的,就紧挨着application创建后,attach执行完后,赋值后又紧接着调用了instrumention的callapplicationoncreat,所以在oncreat里调用getapplicationcontext方法是有返回值的,先记录到这,从main函数到application的attach和oncreate