歡迎轉載,轉載請註明出自:www.androidkaifa.com 安卓開發網
筆者最近在一項目開發中遇到這樣一個需求,要在本身應用中啓動了一個service,這個service用來監聽服務器發過來的推送信息並彈出一個對話框顯示信息,因此須要保證這個service時時運行着,且不能被任務管理或是系統的設置等工具殺掉,若是services是被殺死,則須要自動重啓這service,筆者在網上查詢一下,找到一些相似的問題文章,如今把它在www.androidkaifa.com總結記錄下來,以方便須要實現像我這樣的要求的朋友有幫助,但願你們都能寫永遠不會被KILL掉的進程/服務,也就是不受系統垃圾回收機制(內存管理)影響。
網絡對此問題的解決建議:
(1)
在service中重寫onStartCommand方法,這個方法有三個返回值, START_STICKY是service被kill掉後自動重寫建立@Override public int onStartCommand(Intent intent, int flags, int startId) { return START_STICKY; }
(2)
在Service的onDestroy()中重啓Service.
public void onDestroy() {
Intent localIntent = new Intent();
localIntent.setClass(this, MyService.class); //銷燬時從新啓動Service
this.startService(localIntent);
}
對於(2)此解決方案,筆者本身寫了一個代碼測試了一下,1:若是是在系統的settings中的DOWNLOADED關閉整個應用(Force stop),則這個services類中的onDestory方法沒有監聽到(services類的onDestory方法的log沒有打印日誌),若是是在系統裏的setting中的RUNNING殺掉項目services,則onDestory方法則會監聽到(services類的onDestory方法的log有打印日誌),因此對於此解決方案並非必定適用,2:或是經過別的應用,直接kill掉個人應用時,也是不會調用services類的onDestory方法的,
(3)
再寫另一個apk,用一個廣播來監聽這個APK是否被關閉,若是是關閉了則重啓這個APK,而這裏咱們爲何要用另一個APK?由於被關閉的應用程序不能檢測到本身被關閉的事件,只能接收到其餘應用被關閉的廣播。這個action的recever
public class ProtectorHelperReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String pkg = "com.innofidei.myprotector";// 被kill的應用的包名
String action = pkg + ".action.START_SERVICE";// 重啓service的acition
String str = intent.getData().toString().toLowerCase().replace("package:", "");
String data = intent.getAction();
if (str != null && str.equals(pkg)) {
if (data != null && data.equals("android.intent.action.PACKAGE_REMOVED")) {
File file = new File("/sdcard/" + context.getPackageName() + "/ProtectorHelper.apk");
file.delete();
file.getParentFile().delete();
Intent intent2 = new Intent(context, UninstallActivity.class);
intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent2);
} else {
context.sendBroadcast(new Intent(action));// 通知應用重啓service
}
}
}
}
(4)
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:sharedUserId="android.uid.system">
<application android:icon="@drawable/icon" android:label="@string/app_name"
android:allowClearUserData="false" android:process="system"
android:killAfterRestore="false">
這樣應該能夠了,我也是仿照那些不能被殺死的系統應用的AndroidManifest.xml寫的,可是若要這樣寫,則須要源碼環境編譯能經過,eclipse是沒有這權限編譯的這項目的,
(5)
項目的功能配置文件AndroidManifest.xml 中添加:
android:persistent="true" //在<application>節點下面
(6)提升Android Service 優先級的方法:
咱們先看一下系統一些的進程級別:
進入 $SDK/tools 運行命令:# adb shell dumpsys activity|grep oom_adj 代碼: Running Norm Proc # 6: oom_adj= 0ProcessRecord{43635cf0 12689:com.roiding.netraffic/10028} Running Norm Proc # 5: oom_adj= 7 ProcessRecord{436feda012729:com.android.browser/10006} Running Norm Proc # 4: oom_adj= 8 ProcessRecord{4367e83812761:android.process.acore/10016} Running Norm Proc # 3: oom_adj= 8 ProcessRecord{43691cd812754:com.google.process.gapps/10000} Running PERS Proc # 1: oom_adj=-12 ProcessRecord{435067505941:com.android.phone/1001} Running PERS Proc # 0: oom_adj=-100 ProcessRecord{4348fde0 5908:system/1000} 返 回的一大堆東西,觀察 oom_adj 的值,若是是大於 8 通常就是屬於 backgroud 隨時可能被幹掉,數值越小證實優先級
越高,被幹掉的時間越晚。你看phone的程序是 -12 說明電話就是電話,其餘什麼都幹了了,也的能接電話對吧。
另外還有一個 -100 的,更邪乎由於是 system 若是他也完蛋了,你得系統也就掛了,
Android 系統對於內存管理有本身的一套方法,爲了保障系統有序穩定的運信,系統內部會自動分配,控制程序的內存使用。
當系統以爲當前的資源很是有限的時候,爲了保 證一些優先級高的程序能運行,就會殺掉一些他認爲不重要的程序或者
服務來釋放內存。這樣就能保證真正對用戶有用的程序仍然再運行。若是你的 Service 碰上了這種狀況,多半會先被殺掉。
但若是你增長 Service 的優先級就能讓他多留一會,咱們能夠用 setForeground(true) 來設置 Service 的優先級。爲何是 foreground ? 默認啓動的 Service 是被標記爲 background,當前運行的 Activity 通常被標記爲 foreground,
也就是說你給 Service 設置了 foreground 那麼他就和正在運行的 Activity 相似優先級獲得了必定的提升。
當讓這並不能保證你得 Service 永遠不被殺掉,只是提升了他的優先級。
(7)
請參看個人另外一篇文章《怎樣使一個Android應用不被系統或第三方應用殺死》,
(8)
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
Log.v("TrafficService", "Bind");
state = BINLD;
//使用線程,該線程不會被銷燬
return myBinder;
}
class TrafficBinder extends Binder {
public float his = history;
TrafficService getService(){
return TrafficService.this;
}
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
receiver = new NetReceiver();
IntentFilter nfilter=new IntentFilter();
nfilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
this.registerReceiver(receiver, nfilter);
dealBuffer();
handler.post(createBrod);
Log.v("TrafficService", "Create "+history+" "+todayTraffic+" "+tempTraffic);
super.onCreate();
}
@Override
public boolean onUnbind(Intent intent) {
// TODO Auto-generated method stub
state = UNBINLD;
Log.v("TrafficService", "Unbind");
return true;
}
@Override
public void onRebind(Intent intent) {
// TODO Auto-generated method stub
Log.v("TrafficService", "Rebind");
state = BINLD;;
super.onRebind(intent);
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
handler.removeCallbacks(updateBrod);
momorybuffer();
nManger.cancel(R.layout.notifi);
unregisterReceiver(receiver);
Log.v("TrafficService", "destroy "+history+" "+todayTraffic+" "+tempTraffic);
super.onDestroy();
}
@Override
public boolean stopService(Intent name) {
// TODO Auto-generated method stub
momorybuffer();
nManger.cancel(R.layout.notifi);
Log.v("TrafficService",name.getAction());
Log.v("TrafficService", "stop "+history+" "+todayTraffic+" "+tempTraffic);
return super.stopService(name);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
Log.v("TrafficService","startCommand");
flags = START_STICKY;
return super.onStartCommand(intent, flags, startId);
// return START_REDELIVER_INTENT;
}
//在以上代碼中的onstartCommand返回START_STICKY,同時在destory的最後重啓了服務,這樣就OK了,php