如何让你的App永远在后台存活:对Android进程守护、闹钟后台被杀死的研究

相关阅读:

吊炸天!74款APP完整源码!

123个微信小程序源码分享(附下载)

[干货]2017已来,最全面试总结——这些Android面试题你一定需要



公众号:Java和Android架构

关注回复:Android,iOS,PHP,js,HTML5,Python,机器学习 ,AI,大数据,Hadoop,c++,J2EE等关键字就能免费获取学习资料视频


最近公司要求要做一个提醒功能,一说到提醒,那肯定就和闹钟差不多的意思,那么肯定就要用到AlarmManager。

但是,我们知道,android系统很坑爹,不同的厂商对rom的定制,导致对进程的管理都不太相同,但是如何做到在各个手机上都能一直保持后台执行呢?。

为了解决这个问题,特地去研究了各种保持进程不被杀死的方法。

下面对几种常见的用法进行了分析,并且给出了我自己发现的一个保持进程运行的方法。


方法1:在原生的Android系统上使用AlarmManager

方法2:通过AIDL实现双进程守护机制

方法3:MarsDaemon第三方库,实现进程常驻

方法4:通过AppWiget,android桌面小组件保持进程的运行


下面是具体分析

方法1:在原生的Android系统上使用AlarmManager

“原生”这个词就对这个方法的限定很大了。我尝试了很多次,在原生的操作系统中,不需要特殊的去调用service处理。直接在某个Activity中通过AlarmManager的set和setRepeating方法设置定时后,就去杀了进程,测试结果显示,闹钟还是可以继续响的。但是这种不去特殊处理的,在第三方的rom基本都是不行的,相信大家每人敢用,因此知道就可以了


方法2:通过AIDL实现双进程守护机制

网上有很多关于AIDL实现双进程守护机制的文章,内容都是差不多,关于这种方法,都是通过在MainFest文件中指定某个Service android:process=":remote",这样就可以使这个service单开一个进程来运行。在主进程中有一个MainService,一旦RemoteService所在进程被杀死,MainService就会立刻去重新启动它,同样的,当MainService被杀死了,RemoteService就会去启动MainService,两个进程的两个Service互相监控来实现进程不销毁。


大致方法为:


1、创建一个IMyAIDLInterface.aidl文件

[java] 

  1. // IMyAidlInterface.aidl  

  2. package com.xiaoqi.alarmmanagerdemo;  

  3.   

  4. interface IMyAidlInterface {  

  5.     String getServiceName();  

  6. }  


2、创建一个LocalService:

[java]

  1. public class LocalService extends Service{  

  2.     MyBinder binder;  

  3.     MyConn conn;  

  4.     @Nullable  

  5.     @Override  

  6.     public IBinder onBind(Intent intent) {  

  7.         return binder;  

  8.     }  

  9.   

  10.     @Override  

  11.     public void onCreate() {  

  12.         super.onCreate();  

  13.         binder = new MyBinder();  

  14.         conn = new MyConn();  

  15.     }  

  16.   

  17.     class MyBinder extends IMyAidlInterface.Stub {  

  18.         @Override  

  19.         public String getServiceName() throws RemoteException {  

  20.             return LocalService.class.getSimpleName();  

  21.         }  

  22.     }  

  23.   

  24.     @Override  

  25.     public int onStartCommand(Intent intent, int flags, int startId) {  

  26.         Toast.makeText(LocalService.this, " 本地服务活了", Toast.LENGTH_SHORT).show();  

  27.         this.bindService(new Intent(LocalService.this,RomoteService.class),conn, Context.BIND_IMPORTANT);  

  28.         return START_STICKY;  

  29.     }  

  30.   

  31.     class MyConn implements ServiceConnection{  

  32.         @Override  

  33.         public void onServiceConnected(ComponentName name, IBinder service) {  

  34.             Log.i("yangqing", "绑定上了远程服务");  

  35.         }  

  36.   

  37.         @Override  

  38.         public void onServiceDisconnected(ComponentName name) {  

  39.             Log.i("yangqing", "远程服务被干掉了");  

  40.             Toast.makeText(LocalService.this, "远程服务挂了", Toast.LENGTH_SHORT).show();  

  41.             //开启远程服务  

  42.             LocalService.this.startService(new Intent(LocalService.this,RomoteService.class));  

  43.             //绑定远程服务  

  44.             LocalService.this.bindService(new Intent(LocalService.this,RomoteService.class),conn,Context.BIND_IMPORTANT);  

  45.         }  

  46.     }  

  47.   

  48.     @Override  

  49.     public void onDestroy() {  

  50.         super.onDestroy();  

  51.         //开启远程服务  

  52.         LocalService.this.startService(new Intent(LocalService.this,RomoteService.class));  

  53.         //绑定远程服务  

  54.         LocalService.this.bindService(new Intent(LocalService.this,RomoteService.class),conn,Context.BIND_IMPORTANT);  

  55.   

  56.     }  

  57. }  


3、创建一个RemoteService:

[java] 

  1. public class RomoteService extends Service{  

  2.     MyConn conn;  

  3.     MyBinder binder;  

  4.   

  5.     @Nullable  

  6.     @Override  

  7.     public IBinder onBind(Intent intent) {  

  8.         return binder;  

  9.     }  

  10.   

  11.     @Override  

  12.     public void onCreate() {  

  13.         super.onCreate();  

  14.         conn = new MyConn();  

  15.         binder = new MyBinder();  

  16.     }  

  17.   

  18.     @Override  

  19.     public int onStartCommand(Intent intent, int flags, int startId) {  

  20.   

  21.         Toast.makeText(this, " 远程服务活了", Toast.LENGTH_SHORT).show();  

  22.         this.bindService(new Intent(this, LocalService.class), conn, Context.BIND_IMPORTANT);  

  23.   

  24.         return START_STICKY;  

  25.     }  

  26.   

  27.     class MyBinder extends IMyAidlInterface.Stub {  

  28.         @Override  

  29.         public String getServiceName() throws RemoteException {  

  30.             return RomoteService.class.getSimpleName();  

  31.         }  

  32.     }  

  33.   

  34.     class MyConn implements ServiceConnection {  

  35.   

  36.         @Override  

  37.         public void onServiceConnected(ComponentName name, IBinder service) {  

  38.             Log.i("yangqing", "绑定本地服务成功");  

  39.             // Toast.makeText(RomoteService.this, "绑定本地服务成功", Toast.LENGTH_SHORT).show();  

  40.   

  41.         }  

  42.   

  43.         @Override  

  44.         public void onServiceDisconnected(ComponentName name) {  

  45.             Log.i("yangqing", "本地服务被干掉了");  

  46.             Toast.makeText(RomoteService.this, "本地服务挂了", Toast.LENGTH_SHORT).show();  

  47.   

  48.             //开启本地服务  

  49.             RomoteService.this.startService(new Intent(RomoteService.this, LocalService.class));  

  50.             //绑定本地服务  

  51.             RomoteService.this.bindService(new Intent(RomoteService.this, LocalService.class), conn, Context.BIND_IMPORTANT);  

  52.         }  

  53.   

  54.     }  

  55.   

  56.     @Override  

  57.     public void onDestroy() {  

  58.         super.onDestroy();  

  59.         //开启本地服务  

  60.         RomoteService.this.startService(new Intent(RomoteService.this, LocalService.class));  

  61.         //绑定本地服务  

  62.         RomoteService.this.bindService(new Intent(RomoteService.this, LocalService.class), conn, Context.BIND_IMPORTANT);  

  63.   

  64.     }  

  65. }  


4、在AndroidMainfest文件中注册:

[html]

  1.   

  2.   

  3.   

  4.   

使用方法:

[java] 

  1. Intent service = new Intent(this,LocalService.class);  

  2. startService(service);  

  3. Intent remoteService = new Intent(this,RomoteService.class);  

  4. startService(remoteService);  


这样就可以了,但是经过测试发现,我们在应用管理中,会发现确实有两个进程,我们单独的去关闭一个,另一个马上就会把它开启,但是如果我们之间去杀进程,发现只有在vivo手机中,确实可以保持不被杀死,但是在其他手机中,整个后台进程还是被杀死了。说明这个方法也不是很可靠的。

方法3:MarsDaemon第三方库,实现进程常驻

地址:https://github.com/Marswin/MarsDaemon

守护进程也有第三方库,相信很多人都没想到吧
这个库的使用也非常简单,底层通过jni来实现了进程守护,这边就不给出使用方法了,直接在github上看就行了。

但是我实际使用发现,在华为机器上依然不能进程保持运行,只要一清理,后台的闹钟就没有效果了。但是在某些机型上还是可以用的,可靠性比通过AIDL的双进程守护效果好,可是依然不能保证运行。


方法4:通过AppWiget,android桌面小组件保持进程的运行

尝试了网上的很多方法,都是进程一清理,所以程序都被停止了,尤其在华为手机上,360都没法保持一直运行,因此我觉得这个想让后台服务永久运行的想法越来越不可靠。

我在应用商店上下载了一个排行第一的闹钟软件,但是经过多次测试,结果都是一样,想要后台进行,基本是不可能。QQ是通过一个像素点,一直显示在最前,这种黑科技来保持进程一直在,于是我想到了,如果我们添加一个桌面组件来,这样这个组件也是App的一部分, 但它却一直运行在那,这样是否就可以让进程杀死了,程序还是能运行呢?

于是我测试了一下,写了一个很简单AppWidget组件,在AppWifgetProvider中,写了一个简单的闹钟程序,并且让AppWidget中的TextView的数字一直自增1。写完之后我测了一下,发现这个方法是可行的。即使是在华为手机上,我把进程清理了,闹钟还是会响,AppWidget上的数字也一直在更新。

关于AppWidget的写法网上也很多,这边就不具体给出了。在测试这个方法的时候,我发现刚刚下载的闹钟软件也有桌面小组件,我添加了之后,再进行闹钟测试,居然发现,在进程杀死后,闹钟居然可以继续执行,即使是锁屏状态,很明显,这个软件使用的方法和我想到的是一样的。

通过AppWidget来保持进程中代码的执行,这个应该还其他博客中还没有被提到,这个方法相比其他的方法而言,已经是非常可靠的了。但是这个局限也挺大,就是必须通过一个AppWidget来实现。

关于进程守护已经分析完了,如果有什么更好的方法,欢迎大家分析。

Demo下载地址:http://download.csdn.net/detail/qq_25412055/9651443


关于Java和Android大牛频道

Java和Android大牛频道是一个数万人关注的探讨Java和Android开发的公众号,分享和原创最有价值的干货文章,让你成为这方面的大牛!

我们探讨android和Java开发最前沿的技术:android性能优化 ,插件化,跨平台,动态化,加固和反破解等,也讨论设计模式/软件架构等。由群来自BAT的工程师组成的团队

关注即送红包,回复:“百度” 、“阿里”、“腾讯” 有惊喜!!!关注后可用入微信群。群里都是来自百度阿里腾讯的大牛。

欢迎关注我们,一起讨论技术,扫描和长按下方的二维码可快速关注我们。搜索微信公众号:JANiubility。

如何让你的App永远在后台存活:对Android进程守护、闹钟后台被杀死的研究_第1张图片

公众号:JANiubility

你可能感兴趣的:(Android高阶)