前言:
如果一个应用程序组件是第一次被启动,且这时应用程序也没有其他组件在运行,那么Android系统会为应用程序创建一个包含单个线程的Linux进程。默认情况下,同一个应用程序的所有组件都运行在同一个进程和线程里(其中这个线程叫main线程)。如果组件启动时,已经存在应用程序的进程了(比如:应用程序的其他组件已经在运行中)则组件会在已经存在的进程和线程中启动运行,不过,你也可以指定这个组件运行在那个进程中,同时也可以为任何进程创建额外的线程
一:Ui组件与进程
默认情况下,同一个应用程序的所有组件均运行在同一个进程中,大部分我们也不会去改变它,不过如果需要你也可以给组件指定所属的进程,你可以通过Mainfest配置文件来达到上述目的。
Mainfest文件中每一种元素<activity> <service> <receiver> <service>都支持自定义android:process属性来指定组件的运行进程。设置了此属性就可以实现每个组件在各自的进程中运行,也可以几个组件共享一个进程而其他组件运行在另一个进程,也可以让不同应用程序的组件运行在同一个进程中(已此实现多个应用程序共享一个Linux用户进程Id).赋予同样的权限
其中<application> 用于指定所有的组件运行的进程。
如果内存不足,可又有其他为用户提供紧急服务的进程需要更多内存,Android可能会决定关闭一个进程,那么在此进程的组件也会被销毁,当需要再次工作时,会为这些组件创建一个新进程
在决定关闭哪一个进程时,Android系统会权衡他们相对用户的重要性,比如,相对一个拥有可见Activity的进程,Android系统更加可能去关闭一个Activity在屏幕上看不见的进程,也就是说是否终止进程,取决与运行在此进程中组件的运行状态
二:进程的生命周期(重要性层次结构)
Android进程重要性层次结构:包括,前台进程,可见进程,服务进程,后台进程,空进程
前台进程:用户当前操作所必须的进程,其他满足下面任一条件,均可视为前台进程
1:当前Activity处于onResume状态(正运行着与用户交互的Activity)
2: Service已经启动并处于运行状态(这是要给Service,且Service被绑定在当前正在与用户交互的Activity上)
3:运气着前台服务的Service(服务以startForeground的方式被启动)
4:其中运行着正在执行生命周期的方法(onCreate ---onStart----onDestory)的Service
5: 运行着正在执行onReceiver的BroadcastReceiver
可见进程:没有前台组件,但仍然会影响用户在屏幕上所见内容的进程,满足下面任一条件都可以视为可见进程
1:运行着不在前台的Activity, 但是用户仍然可见到此Activity(比如Activity打开了一个透明的Activity 被调用了onPause)。
2: 运行着被可见(或前台)activity绑定的 Service
服务进程:运行着startService()启动的服务,它不会升级为上述两种级别的进程,尽管服务不直接可用户交互关联,但是他们通常在执行一些用户关系的操作(比如在后台播放音乐或从网络上下载数据),因此除非内存不足以维持前台进程或者可见进程,通常系统会保持服务进程的运行
后台进程:包含了用户不可见的Activity(Activity运行了onStop函数)的进程,这些进程对用户没有任何影响,系统可以在任意时间终止他们,已回收内存共前台进程,可见进程,服务进程使用。
通常情况下,会有很多后台进程在运行,所以他们被保存在一个LRU(最近最少使用)列表中,以确保最近被用户使用的activity最后一个被终止。
空进程:不含任何活动应用程序组件的进程,保留这种进程的唯一目的就是用作缓存,已改善下次在此进程中运行组件的启动时间。
进程级别的规则
1:根据进程中目前活跃组件的重要程度,Android会给进程评估一个尽可能高的级别,例如:如果一个进程运行着一个服务和一个用户可见的Activity,则此进程会被Android系统评定为可见进程,而不是服务进程
2:一个进程的级别还会由于其他进程的依赖而被提高,(为其他进程提供服务的进程级别永远不会低于使用此服务的进程),比如:A进程中的Content Provider为进程B中的客户端提供服务,或者进程A的服务被进程B中的组件调用,那么进程A至少被视为进程B同等级别进程
PS: 因为运行服务的进程比后台Activity的进程级别高,所以,如果activity需要运行启动一个长时间的运行操作,那么为其启动一个 Service比简单创建要给 工作线程要好。尤其在此操作时间比activity本身存在的时间还要更长久的情况下。
比如:一个Activity需要把图片上传至web网站,那么我们不应该在Activity创建工作线程,来实现这个功能,应该为这个Activity 启动一个 Service, 那么这样即使用户离开了 Activity上传功能还是会继续,所以不论什么情况下,使用了service至少可以保证“服务进程”的优先级。同样的道理:如果时在接收到广播的情况下,onReceiver也不建议启动工作线程处理 耗时任务,而是启动Service来处理耗时任务
进程之间通信:Android利用远程过程调用(remote produce call)提供一种进程间通信(IPC)机制,通过这种机制,被activity或其他应用程序组件调用的方法将会在远程被执行,而所有的结果将会返回给调用者。所以这就要求了需要将方法调用和数据分解到 操作系统级别,并将其从本地的进程和地址空间传输至远程的进程和地址空间,然后在远程进程中重新组装并调用。执行后的返回值将返回给调用者。Android提供了执行IPC事务所需的的全部代码,因此我们只需要把注意力放在定义和RPC接口的编程上。那么进程间的通信方式有: Binder 管道 和 Socket
线程
Andorid应用程序启动时,系统会为应用程序创建一个名为“main”的主线程,主线程非常重要,它负责处理与UI相关的事件,如用户触摸,屏幕绘制等,这个主线程就是应该程序与Android ui组件包进行交互线程,因此主线程也叫ui线程
Android单线程模式必须遵守下面两个规定
1:不要阻塞Ui线程(就是说Ui线程不能进行耗时操作)
2: 不要在ui线程之外访问Android的Ui组件包(也就是Android平台只运行主线程修改UI组件)
系统并不会为某个组件的实例单独创建单独的线程,运行与同一个进程的组件都是Ui线程实例话的,对每个组件的系统调用也是经过Ui线程分发的。
举个例子:当用户触摸屏幕上的按钮,应用程序的UI线程把事件分发给widget,widget先记录状态,在发一个消息到请求队列中,UI线程从事件队列中,取出此消息,波过你通知widget重绘自己,如果应用程序在与用户交互的同时,又在执行一些繁重的任务,那么单线程模式可能会导致性能运行下降,除非应该程序运行时机刚好合适,否则Ui线程一旦被阻塞,所有事件不能被分发,包括绘图事件,那么从用户的角度来看,程序就好像时挂掉了一样所以,Android在Ui程序被阻塞了一定时间(5s)系统就会给用户提示 ANR异常,
3:守护线程,用户线程
线程根据作用可分为用户线程和守护线程,一般我们平时执行具体业务逻辑的线程都是用户线程,而守护线程则一般是为正在运行的用户线程提供便利服务的。比如JVM垃圾回收期的线程就是守护线程,它的作用就是回收其他普通用户线程执行完成遗留下的内存资源。
PS: 如果处理用户业务的用户线程在执行完各自的业务逻辑后,守护线程仍然存在的情况下,那么虚拟机实例还有必要存在吗 ?答案是:没有必要,JVM不会由于守护线程在运行而继续存在,它会在所有用户线程终止后退出
所以:我们不应该把较重要的操作:文件,数据库的读取,放在守护线程,因为这样做的话,它可能在任何一个操作中间发生中断。守护线程不仅仅局限于系统级别,我们可以通过设置setDaemon(true)方法设置为守护线程