如何讓你的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. <service android:name="com.xiaoqi.alarmmanagerdemo.LocalService">  

  2. </service>  

  3. <service android:name="com.xiaoqi.alarmmanagerdemo.RomoteService" android:process=":romoteservice">  

  4. </service>  

使用方法:

[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。

公衆號:JANiubility

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章