最近项目用到Service常驻后台,研究了一下发现手Q和微信都是使用了双进程来保证一键清理后自动复活,copy网上双进程Service的例子,再结合onTrimMemory(),基本实现一键清理后自动复活。

使用双进程Service,关键是在AndroidManifest.xml里面定义Service时加入Android:process=":service1"

 <service android:enabled="true" android:name="com.service.demo.Service1" android:process=":service1"></service>
<service android:enabled="true" android:name="com.service.demo.Service2" android:process=":service2"></service>

双进程Service可以让2个进程互相保护,其中一个Service被清理后,另外没被清理的进程可以立即重启进程。

--------以下onTrimMemory的解释引用于网络

onTrimMemory()是Android 4.0之后提供的API,系统会根据不同的内存状态来回调。根据不同的内存状态,来响应不同的内存释放策略。OnTrimMemory的参数是一个int数值,代表不同的内存状态:

TRIM_MEMORY_COMPLETE:内存不足,并且该进程在后台进程列表最后一个,马上就要被清理
TRIM_MEMORY_MODERATE:内存不足,并且该进程在后台进程列表的中部。
TRIM_MEMORY_BACKGROUND:内存不足,并且该进程是后台进程。
TRIM_MEMORY_UI_HIDDEN:内存不足,并且该进程的UI已经不可见了。 
以上4个是4.0增加
TRIM_MEMORY_RUNNING_CRITICAL:内存不足(后台进程不足3个),并且该进程优先级比较高,需要清理内存
TRIM_MEMORY_RUNNING_LOW:内存不足(后台进程不足5个),并且该进程优先级比较高,需要清理内存
TRIM_MEMORY_RUNNING_MODERATE:内存不足(后台进程超过5个),并且该进程优先级比较高,需要清理内存 
以上3个是4.1增加。

本文的例子源码可以到这里下载http://pan.baidu.com/s/1qW3KvtM

以下是本文运行DEMO的结果:开启服务后双进程Service分别启动(Toast显示出来),然后使用“一键加速”来清理内存,双进程Service被逐一清理(触发Service的onTrimMemory()),但后面又分别重新启动了。

代码分析 :

AndroidManifest.xml

 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.servicetest2"
android:versionCode="1"
android:versionName="1.0" > <uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="19" /> <application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" > <activity android:name="com.service.demo.Main">
<intent-filter >
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- 关键代码 -->
<service android:enabled="true" android:name="com.service.demo.Service1" android:process=":service1"></service>
<service android:enabled="true" android:name="com.service.demo.Service2" android:process=":service2"></service> </application> </manifest>

Service1.java

 package com.service.demo;

 import java.util.List;

 import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.Service;
import android.app.ActivityManager.RunningServiceInfo;
import android.content.ComponentCallbacks;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.res.Configuration;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast; /**
*
* @author hellogv
*
*/
public class Service1 extends Service { private String TAG = getClass().getName();
// 用于判断进程是否运行
private String Process_Name = "com.example.servicetest2:service2"; /**
*启动Service2
*/
private StrongService startS2 = new StrongService.Stub() {
@Override
public void stopService() throws RemoteException {
Intent i = new Intent(getBaseContext(), Service2.class);
getBaseContext().stopService(i);
} @Override
public void startService() throws RemoteException {
Intent i = new Intent(getBaseContext(), Service2.class);
getBaseContext().startService(i);
}
}; @Override
public void onTrimMemory(int level){
Toast.makeText(getBaseContext(), "Service1 onTrimMemory..."+level, Toast.LENGTH_SHORT)
.show(); keepService2();//保持Service2一直运行 } @Override
public void onCreate() {
Toast.makeText(Service1.this, "Service1 onCreate...", Toast.LENGTH_SHORT)
.show();
keepService2();
} /**
* 判断Service2是否还在运行,如果不是则启动Service2
*/
private void keepService2(){
boolean isRun = Utils.isProessRunning(Service1.this, Process_Name);
if (isRun == false) {
try {
Toast.makeText(getBaseContext(), "重新启动 Service2", Toast.LENGTH_SHORT).show();
startS2.startService();
} catch (RemoteException e) {
e.printStackTrace();
}
}
} @Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
} @Override
public IBinder onBind(Intent intent) {
return (IBinder) startS2;
}
}

Service2.java

 package com.service.demo;

 import java.util.List;

 import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.ActivityManager.RunningServiceInfo;
import android.app.Application;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.widget.Toast;
/**
*
* @author 掌缘生灭
*
*/
public class Service2 extends Service {
private String TAG = getClass().getName();
private String Process_Name = "com.example.servicetest2:service1"; /**
*启动Service1
*/
private StrongService startS1 = new StrongService.Stub() { @Override
public void stopService() throws RemoteException {
Intent i = new Intent(getBaseContext(), Service1.class);
getBaseContext().stopService(i);
} @Override
public void startService() throws RemoteException {
Intent i = new Intent(getBaseContext(), Service1.class);
getBaseContext().startService(i); }
}; @Override
public void onTrimMemory(int level){
Toast.makeText(getBaseContext(), "Service2 onTrimMemory..."+level, Toast.LENGTH_SHORT)
.show();
keepService1();
} public void onCreate() {
Toast.makeText(Service2.this, "Service2 onCreate...", Toast.LENGTH_SHORT).show();
keepService1();
} /**
* 判断Service1是否还在运行,如果不是则启动Service1
*/
private void keepService1(){
boolean isRun = Utils.isProessRunning(Service2.this, Process_Name);
if (isRun == false) {
try {
Toast.makeText(getBaseContext(), "重新启动 Service1", Toast.LENGTH_SHORT).show();
startS1.startService();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
} @Override
public IBinder onBind(Intent intent) {
return (IBinder) startS1;
} }

Utils.java

package com.service.demo;

import java.util.List;

import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.Context; public class Utils { /**
* 判断进程是否运行
* @return
*/
public static boolean isProessRunning(Context context, String proessName) { boolean isRunning = false;
ActivityManager am = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE); List<RunningAppProcessInfo> lists = am.getRunningAppProcesses();
for (RunningAppProcessInfo info : lists) {
if (info.processName.equals(proessName)) {
isRunning = true;
}
} return isRunning;
}
}

StrongService.aidl

 package com.service.demo;
interface StrongService{
void startService();
void stopService();
}

(转)Android Service 双进程常驻后台(2)的更多相关文章

  1. Android 保持Service不被Kill掉的方法--双Service守护 && Android实现双进程守护

    本文分为两个部分,第一部分为双Service守护,第二部分为双进程守护 第一部分: 一.Service简介:Java.lang.Object ↳Android.content.Context  ↳an ...

  2. 保持Service不被Kill掉的方法--双Service守护 && Android实现双进程守护

    本文分为两个部分,第一部分为双Service守护,第二部分为双进程守护 第一部分: 一.Service简介:Java.lang.Object ↳Android.content.Context  ↳an ...

  3. Android实现双进程守护 (转)

    做过android开发的人应该都知道应用会在系统资源匮乏的情况下被系统杀死!当后台的应用被系统回收之后,如何重新恢复它呢?网上对此问题有很多的讨论.这里先总结一下网上流传的各种解决方案,看看这些办法是 ...

  4. Android实现双进程守护

    做过android开发的人应该都知道应用会在系统资源匮乏的情况下被系统杀死!当后台的应用被系统回收之后,如何重新恢复它呢?网上对此问题有很多的讨论.这里先总结一下网上流传的各种解决方案,看看这些办法是 ...

  5. android正在运行进程和后台缓存进程的区别

    正在运行的进程:需要占用一定的cpu资源和RAM(内存)空间,多少的话看是什么应用,要消耗一定的电量,影响手机速度等性能. 后台缓存的进程:不需要占用cpu资源,会在RAM中写入一部分数据,当下次打开 ...

  6. Android MarsDaemon实现进程及Service常驻

    前段时间.就讨论过关于怎样让Service常驻于内存而不被杀死,最后的结论就是使用JNI实现守护进程,可是不得不说的是,在没有改动系统源代码的情况下,想真正实现杀不死服务,是一件非常难的事情.眼下除了 ...

  7. Android 进程常驻(0)----MarsDaemon使用说明

    版权声明:本文为博主原创文章,未经博主允许不得转载. 这是一个轻量级的库,配置几行代码,就可以实现在Android上实现进程常驻,也就是在系统强杀下,以及360获取root权限下,clean mast ...

  8. Android 进程常驻----开机广播的简单守护以及总结

    这是一个轻量级的库,配置几行代码,就可以实现在Android上实现进程常驻,也就是在系统强杀下,以及360获取root权限下,clean master获取root权限下都无法杀死进程 支持系统2.3到 ...

  9. Android 进程常驻、进程守护、进程保活技术的总结

    转载自:http://blog.csdn.net/marswin89/article/details/50917098 这是一个轻量级的库,配置几行代码,就可以实现在Android上实现进程常驻,也就 ...

随机推荐

  1. 《A First Course in Probability》-chape4-离散型随机变量-几种典型分布列

    超几何分布: 超几何分布基于这样一个模型,一个坛子中有N个球,其中m个白球,N-m个黑球,从中随机取n(不放回),令X表示取出来的白球数,那么: 我们称随机变量X满足参数为(n,m,M)的超几何分布. ...

  2. itunes备份文件解析入门

    itunes提供给设备备份的功能,不知道怎么备份的话可以戳一下这个看一下:http://jingyan.baidu.com/article/92255446ea8f46851648f4a4.html ...

  3. spark高级排序彻底解秘

    排序,真的非常重要! RDD.scala(源码) 在其,没有罗列排序,不是说它不重要! 1.基础排序算法实战 2.二次排序算法实战 3.更高级别排序算法 4.排序算法内幕解密 1.基础排序算法实战 启 ...

  4. coco2dx 精灵类

    CCSize size = CCDirector::sharedDirector()->getWinSize(); CCSprite *bg = CCSprite::create("H ...

  5. webapp 慎用setInterval、setTimeout

    其实这片文章刚开始我啥也没写的,但也有20多的访问量,所以觉得大家还是比较关注这个问题,所以找机会写下. 问题的引出: 为什么我说的时webapp中慎用setInterval.setTimeout, ...

  6. 使用GitHub管理源代码

    作为一个开发员,源码的管理是一个头等大事来的,想象一下,修改完成却发现文件丢失了,该怎么办?有了源代码管理工具,能够帮助我们查看某个代码文件的修改内存及历史修改记录. 作为.Net开发员,我使用过VS ...

  7. PAT 1016. Phone Bills

    A long-distance telephone company charges its customers by the following rules: Making a long-distan ...

  8. hibernate关联关系映射详解

    词汇解释 关系:事物之间相互作用.相互联系的状态.范围最大. 联系:在关系数据库中表示实体与实体之间的联系,1:1,1:n,m:n. 关联:表示对象之间的关系,既有数量性,又有方向性:动词:将对象之间 ...

  9. WinForm TextBox自定义扩展方法数据验证

    本文转载:http://www.cnblogs.com/gis-crazy/archive/2013/03/17/2964132.html 查看公司项目代码时,存在这样一个问题:winform界面上有 ...

  10. 分分钟解决iOS开发中App启动广告的功能

    前不久有朋友需要一个启动广告的功能,我说网上有挺多的,他说,看的不是很理想.想让我写一个,于是乎,抽空写了一个,代码通俗易懂,简单的封装了一下,各种事件用block回调的,有俩种样式的广告,一种是全屏 ...