默认下,同一个应用的所有组件都运行在同一个进程中。当然也可以在manifest清单文件中设置组件运行的进程。
组件元素 activity、service、receiver、provider,都有一个process属性可以指定组件运行在哪个进程中。这个属性可以设置为每个组件运行在自己的进程中,或者设置进程同名与其他一些组件共享一个进程。
Android会在某些时刻决定关闭一个进程,比如内存剩余较小并且其他进程更迫切需要内存时,某些进程会被关闭时,且进程中的组件们都被销毁.如果重新需要这些组件工作时,进程又会被创建出来。
系统不会为每个组件的实例分别创建线程。所有运行于一个进程的组件都在主线程(UI线程)中被实例化,并且系统对每个组件的调用都在这个线程中派发,且只能在UI线程中管理的你的界面。
可以 线程 进程 应用 打个比方:
线程(Thread):流水线 、 进程(process): 车间 、 应用:工厂
为什么使用多线程?
线程如同一条流水线,当我们执行一些比如网络连接或数据库请求这样的耗时操作,会造成该线程阻塞。而我们又需要在主线程(UI线程)中对整个界面进行响应。所以为了不阻塞UI线程,提高应用程序的性能,需要使用多线程来操作。
为什么使用多进程?
在Android系统中,每个进程都有一个内存限制。如果一个应用可以多有个进程,那么这个应用可以有更多的内存来运行,使我们的应用内存限制变大,优化程序的速度。
前台进程(Foreground process):
A. 拥有用户正在交互的 Activity( onResume()状态)
B. 正在与bound绑定服务交互的 Activity
C. 正在“前台”运行的 Service(startForeground()被调用)
D. 生命周期函数正在被执行的 Service(onCreate()、onStart() 或 onDestroy())
E. 正执行 onReceive() 方法的 BroadcastReceiver
(该进程优先级别最高,杀死前台进程需要用户的响应。)
可见进程(Visible process):
该进程并不是在最前端,并没有得到焦点,但是我们却能看到它们。
A. 拥有不在前台、但仍对用户可见的 Activity(例如弹出一个对话框的Activity)
B. 绑定到可见进程(或前台进程)中的Activity 的 Service
服务进程(Service process):
A. 正在运行的通过 startService() 启动的,且不属于上述两个更高进程状态的Service
后台进程(Background process):
A. 不可见状态的Activity进程
空进程(Empty process):
A. 没有运行任何应用组件的进程,保留这个进程主要是为了缓存的需要,待下次相关组件运行时直接从内存中获取数据,缩短对数据获取的时间。
进程等级判断原则:当存在多种等级的进程状态时,优先考虑优先级较高的进程。
在Android系统,当用户退出应用程序之后,应用程序的进程还是会存在于系统中,这样方便于程序的再次启动。
但随着打开的应用程序数量的增加,系统内存会变得不足,就需要杀掉一部分应用程序的进程以释放内存空间。
至于是否需要杀死哪些进程需要被杀死,是通过Low Memory Killer机制来进行判定的。
Low Memory Killer是通过进程的oom_adj与占用内存的大小决定要杀死的进程,oom_adj越小越不容易被杀死。
有一组系统内存临界值和与之一一对应的一组oom_adj值,当系统剩余内存位于内存临界值中的一个范围内时,如果一个进程的oom_adj值大于/等于这个临界值对应的oom_adj值,该进程就会被杀掉。
轻量化进程:按照Low Memory Killer的杀死进程的规则,应尽量让Service在后台做较少的事情,且及时释放内存资源。
利用service提升进程权限: 调用 startForeground方法将service置为“前台进程”,不过这样我们需要发送一个Notification通知。
如何取消通知:
1. 在Android 4.3之前,可以通过构造一个空的Notification使通知栏不会显示我们发送的Notification。
2. 在Android 4.3之后,谷歌不再允许构造空的Notification。但有一个奇葩的方法:
可以将两个同进程的Service都通过startForeground设置为前台进程,但它们使用的是同一个ID的Notification通知,这样只会产生一个Notification。然后其中一个Service取消前台通知,那么该通知会被关闭。这样剩下的Service还是一个前台Service,且通知栏没有通知。
在application标签中加入 android:persistent=“true”
在androidmanifest.xml中的application标签中加入android:persistent="true" 属性后能够达到保证该应用程序所在进程不会被LMK杀死,异常出现后也可以自启。但前提是应用程序必须是系统应用,即应用程序不能采用通常的安装方式。必须将应用程序的apk包直接放到/system/app目录下。而且必须重启系统后才能生效。
利用Service机制重启:
安卓系统设计Service时,可以通过其onStartCommand方法中返回不同的值告知系统,让系统在Service因为内存不足被杀掉后可以在资源不紧张时重启。
START_NOT_STICKY
如果系统在onStartCommand()方法返回之后杀死这个服务,那么直到接受到新的Intent对象,这个服务才会被重新创建。
START_STICKY
如果系统在onStartCommand()返回后杀死了这个服务,系统就会重新创建这个服务并且调用onStartCommand()方法,但是它不会重新传递最后的Intent对象,系统会用一个null的Intent对象来调用onStartCommand()方法。
在这个情况下,除非有一些被发送的Intent对象在等待启动服务。这适用于不执行命令的媒体播放器(或类似的服务),它只是无限期的运行着并等待工作的到来。
START_REDELIVER_INTENT
如果系统在onStartCommand()方法返回后,系统就会重新创建了这个服务,并且用发送给这个服务的最后的Intent对象调用了onStartCommand()方法。任意等待中的Intent对象会依次被发送。这适用于那些应该立即恢复正在执行的工作的服务,如下载文件。
虽然在这种情况可以让Service被系统重启的,但不能立即被重启。而且在某些定制ROM上失效。
双进程守护:
设计AB两个不同进程,A进程里面轮询检查B进程是否存活,没存活的话将其拉起,同样B进程里面轮询检查A进程是否存活,没存活的话也将其拉起,而后台逻辑可以随便放在某个进程里执行即可。
使用两个进程分别装载两个Service,两个Service相互轮询唤醒:
public class FirService extends Service {
public final static String TAG = "com.example.servicedemo.FirService";
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
thread.start();
return START_STICKY;
}
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
Log.e(TAG, "FirService Run: "+System.currentTimeMillis());
boolean b = Util.isServiceWorked(FirService.this, "com.example.servicedemo.SecService");
if(!b) {
Intent service = new Intent(FirService.this, SecService.class);
startService(service);
Log.e(TAG, "Start SecService");
}
}
};
timer.schedule(task, 0, 1000);
}
});
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}
--------------------------------------
public class SecService extends Service {
public final static String TAG = "com.example.servicedemo.SecService";
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand");
thread.start();
return START_REDELIVER_INTENT;
}
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
Timer timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
Log.e(TAG, "SecService Run: " + System.currentTimeMillis());
boolean b = Util.isServiceWorked(SecService.this, "com.example.servicedemo.FirService");
if(!b) {
Intent service = new Intent(ServiceTwo.this, FirService.class);
startService(service);
}
}
};
timer.schedule(task, 0, 1000);
}
});
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}
-----------------------------------
public class Util {
public static boolean isServiceWorked(Context context, String serviceName) {
ActivityManager myManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ArrayList runningService = (ArrayList) myManager.getRunningServices(Integer.MAX_VALUE);
for (int i = 0; i < runningService.size(); i++) {
if (runningService.get(i).service.getClassName().toString().equals(serviceName)) {
return true;
}
}
return false;
}
}
利用静态广播接收器重启进程:
使用静态注册的广播接收器BroadcastReceiver来监听一些系统广播/其他应用发出的广播在onReceive中重启进程。
无法接受到系统?:
1. 在Android 3.1之后,处于stopped状态的应用无法接收到系统广播。
2. 如果一个应用在安装后从来没有启动过,或者已经被用户强制停止了,那么这个应用就处于停止状态(stopped state)。
3. 如果想使处于stopped状态的应用也接收到广播,需要在intent中增加FLAG_INCLUDE_STOPPED_PACKAGES这个Flag。要注意的是,用户无法自定义系统广播。
4. 有些广播只有静态接收器可以接收得到。
5. 深度定制ROM使应用重回STOPPED状态
与系统Service捆绑 : NotificationListenerService
NotificationListenerService是通过系统调起的服务,当有应用发起通知的时候,系统会将通知的动作和信息回调给NotificationListenerService。
-------------------
public class NotificationService extends NotificationListenerService {
@Override
public void onNotificationPosted(StatusBarNotification sbn) {
}
@Override
public void onNotificationRemoved(StatusBarNotification sbn) {
}
}
当系统发现某应用产生通知或者用户删除某通知,都会回调该服务的上述这两个函数,函数的参数StatusBarNotification包含着该通知的具体信息。.
其他:全家桶/SDK唤醒、手机厂商的白名单定制
进程保活要回到用户体验。有的进程保活不能做到性能优化,反而在不断重启费电、亦或如幽灵般重复出现在用户面前。在某些应用场景里,有的进程保活起到了应有的作用,比如音乐播放时的前台Service…..
流氓的进程保活只会搞坏Android 生态环境,伤害 Android 平台开发者等人的利益。当然,Google也不会让这么流氓方式胡作非为。
http://blog.csdn.net/aigestudio/article/details/51348408
http://www.jianshu.com/p/63aafe3c12af
http://www.cnblogs.com/angeldevil/archive/2013/05/21/3090872.html
…