Android应用程序运行时会先读取AndroidManifest.xml清单文件,根据清单文件中的配置信息设置应用程序的基本信息,通过过滤条件查找到入口的Activity,并查找到对应的类名,然后创建该类的实例。接着会调用该类的onCreate
方法设置Activity显示界面。
Android应用的启动流程
你所看到的手机桌面Launcher也是继承自Activity的,当安装完以一个APP之后会在手机桌面Launcherr上生成 以一个对应的APP图标。首次点击图标时Launcher会启动图标对应APP的首页Activity,一般而言启动的都是项目工程中的MainActivity,其实这个过程是一个Activity的启动的过程,与在APP内部启动一个Activity不同的是:点击桌面Launcher首次启动APP时会先去建立APP对应的进程,然后再执行ActivityThread的main()方法去创建对应的Application,最后再启动首页Activity。
当用户点击APP图标时会启动Launcher与应用程序,Launcher继承自Activity并实现了点击长按监听。此时Luncher会通过Intent发送startActivity请求,通过binder机制调用ActivityManagerService通讯,经过一些列操作后调用startProcessLocked方法,并通过Socket通道传递参数给Zygote进程。此时Zygote进程会调用ZygoteInit.main()方法产生一个新的进程并返回PID,最后调用ActivityThread.main方法来实例化ActivityThread对象。此时Activity进程真正开始...
当点击桌面Launcher首次进入APP时,会走Activity的startActivity()的过程,在启动一个新的Activity之前会先执行当前Activity的onPause()方法,会将当前Activity给Pause掉。如果是点击桌面Launcher首次进入APP的话,这个当前的Activity指的是桌面Launcher的Activity。当前Activity执行onPause()之后,如果当前应用的进程已经创建,这种情况下指得是在APP内部的Activity的跳转,那么就会去通过ActivityManagerService中持有的ActivityThread中的ApplicationThread这个Binder对象来立即创建一个新的Activity,并执行该Activity声明周期的方法。如果当前应用的进程没有创建也就是首次进入APP,那么这个时候会先通过Process.start()方法来创建一个进程,在创建的过程中会去调用ActivityThread的main()方法,在这个main()方法中会创建一些必备的东西比如主线程的Looper等,并且在main()方法中会执行Application的创建过程,通过ActivityManagerService来创建一个Application,在创建完成后会启动一个Activity,这个Activity值得是默认启动的首页Activity,也就是通常所说的MainActivity。
清单文件AndroidManifest.xml
Application的创建过程
整个Android应用启动的入口是ActivityThread的main()方法,Application的创建也是在这个main()方法中。
Application类
- Applicaton是维护全局状态的基类,Android系统会在启动APP进程时创建一个Application对象,Application中的对象变量是属于整个系统的。
- 在启动APP时会创建Application对象,所以Application对象诞生于其他任何组件对象之前,并且一直存活直到APP进程结束。
- 默认情况下Android系统会为每个APP分配 一个进程,进程名称是项目的包名,当进程启动时Android系统会创建Application对象并调用对象的
onCreate
方法。 - Application在项目运行过程中不会改变,而Activity在切换过程中会有不断地创建和销毁,Service服务切换也会创建和销毁,但是Application则不会改变。
- Application对象由Android系统管理,其回调函数都运行于主线程(UI线程),回调函数包括
onCreate
创建、onConfigurationChanged
系统配置变更(包括屏幕方向变化、系统语言变化等)、onLowMemory
释放内存 - Application对象是全局可访问的,而且全程陪同APP进程,适合共享状态,初始化应应用所需的服务。
- 静态单例也可以是西安全局状态的共享
Application和Activity、Service一样都是Android框架的系统组件,当APP启动时系统会创建一个Application对象用来存储系统的信息。Android系统会自动为每个程序运行时创建一个Application类的对象且只创建一个,所以Application可以说是单例(singleton)模式的一个类。
通常无需手动指定Application,系统会自动创建。如果需要手工创建只需要创建一个继承自Application的类并在AndroidManifest.xml清单文件中的
标签中进行注册,也就是给
标签增加android:name
属性。
继承Application的类主要需要重写父类的onCreate()
方法,因为android.app.Application
包中的onCreate()
方法才是真正的Android程序的入口点。在onCreate()
方法主要用于创建时初始化变量的值,然后在整个应用中的各个文件中就可以对该变量进行操作。
$ vim MainApplication.java
package com.weihuagu.receiptnotice;
import android.app.Application;
import android.content.Intent;
import com.tao.admin.loglib.TLogApplication;
import com.tao.admin.loglib.IConfig;
public class MainApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
startNotificationService();
initLogConfig();
}
private void initLogConfig(){
TLogApplication.initialize(this);
IConfig.getInstance().isShowLog(false)//是否在logcat中打印log,默认不打印
.isWriteLog(true)//是否在文件中记录,默认不记录
.tag("GoFileService");//logcat 日志过滤tag
}
private void startNotificationService(){
startService(new Intent(this, NotificationCollectorMonitorService.class));
}
}
android.app.Application
类包含了四个公开的方法
void onConfigurationChanged(Configuration newConfig)
void onCreate()
void onLowMemory()
void onTerminate()
Application的生命周期
-
onCreate
在创建应用程序时创建 -
onTerminate
当终止应用程序对象时调用,不保证一定被调。
当程序是被内核终止以便为其他应用程序释放资源,那么将不会提醒,并且不会调用Application
对象的onTerminate()
方法而直接终止进程。 -
onLowMemory
当后台程序已经终止资源还匮乏时会调用此方法,好的应用程序一般会在此方法中释放一些不必要的资源来应付当后台程序已经终止,前台应用程序内存仍不足够时的情况。 -
onConfigurationChanged
配置改变时触发
Application被杀死的情况
为了决定在内存较低时杀掉哪个进程,Android会根据运行在这些进程内的组件以及状态将进程划分成一个重要程度层次,其重要程度按一下规则排序。
- 前端进程可以是一个持有运行在屏幕最前端并与用户交互的Activity的进程(
onResume()
方法被调用时),也可以是持有一个正在运行的IntentReceiver(正在执行自己的onReceiveIntent()
方法)的进程。在系统中,只会有少数这样的进程,除非内存已经低到不够这些进程运行,否则系统不会主动杀掉这些进程。此时设备通常已经达到需要内存整理的状态,所以杀掉这些进程是为了不让用户界面停止响应。 - 可视进程是持有一个被用户可见,但没有显示在最前端(onPause方法被调用时)的Activity进程。比如这种进程通常出现在一个前端Activity以一个对话框出现并保持前一个Activity可见时,这种进程被系统认为是极为重要的,并且通常不会被杀掉,除非为了保持所有前端进程正常运行不得不杀掉这些可见进程。
- 服务进程是持有有一个Service的进程,该Service是由startService()方法启动的,尽管这些进程用户不能直接看到,但通常它们所作的工作是用户十分关注的。比如在后台播放MP3或在后台下载上传文件。所以,除非为了保持所有的前端进程和可视进程正常运行外,,系统是不会杀掉服务进程的。
4.后台进程是持有一个不再被用户可见的Activity(onStop方法被调用时)的进程,这些进程不会直接影响用户体验,加入这些进程已经完成了自己的生命周期,系统会为前三种进程释放内存时随时杀掉这些后台进程。通常会有很多的后台进程在运行,所以这些进程被存放在一个LRU列表中,以保证在低内存的时候,最后一个被用户看到的进程会被最后杀掉。
5.空进程是没有持有任何活动应用组件的进程,保留这种进程的唯一理由是为了提供一种缓存机制,缩短应用下次运行时的启动时间。就其本身而言,系统杀掉这些进程的鳄目的是为了在这些空进程和底层核心缓存之间平衡整个系统的资源。
当启动Application时系统会创建一个进程ID(PID),所有的Activity都会在此进程上运行。在Application创建的时候会初始化全局变量,同一个应用的所有Activity都可以获取到这些全局变量的值。换句话说,在某个Activity中改变了全局变量的值会影响到同一个应用中其他Activity中的值。
Application对象的生命周期是整个程序中最长的,基本上等同于应用的生命周期。因为是全局单例的,所以在 不同的Activity、Service中获取得到的对象都是同一个对象。因此可以通过Application来进行一些操作,比如数据传递、数据共享、数据缓存等。
Application传递数据
假如有一个ActivityA跳转到ActivityB并需要推荐一些数据,通常的做法是使用Intent.putExtra()
方法让Intent
携带,或者使用一个Bundle将信息让Intent推荐Bundle对象实现传递。但这样做的问题在于Intent和Bundle所能携带的数据类型都是基本数据类型,如果想要实现复杂数据类型传递就比较麻烦,通常需要实现Serializable或Parcellable接口,这其实是Android的一种IPC数据传输的方法。如果两个Activitty在同一个进程中为什么还需要这么麻烦呢?只需将要传递的数据引用传递过去即可。实现的基本思路是在Application中创建一个HashMap,以字符串为索引,Object为值得方式。在ActivityA中将需要传递的对象放入HashMap,然后通过Intent或其他途径将索引字符串传递给ActivityB,AactivityB会根据这个字符串在HashMap中获取出目标对象。只要再向下转型就实现了对象的传递。
Application数据缓存
一般习惯会再Application中建立两个HashMap,一个用于数据传递,一个用于缓存数据。比如有一个Activity需要从网站中获取数据,获取完毕后可以将数据缓存到Application中,当页面设置到其他Activity再回来时,可以直接使用给缓存好的数据。但如果需要缓存一些大量数据,最好是缓存一些软引用(SoftReference),并将这些数据缓存到本地ROM或SD卡上。如果再Application中的缓存不存在,可以从本地缓存中查找,如果本地缓存的数据也不存在则再从网络中获取。