timerTask = new TimerTask() {
@Override
public void run() {
Log.d(MainActivity.TAG, "服务运行中,count: " + count);
count++;
}
};
timer.schedule(timerTask, 0, 1000);
}
/**
- 结束定时任务
*/
private void stopTask() {
if (timer != null) {
timer.cancel();
timer = null;
}
if (timerTask != null) {
timerTask.cancel();
timerTask = null;
}
count = 0;
}
@Override
public void onDestroy() {
stopTask();
Log.d(MainActivity.TAG, “销毁前台服务”);
super.onDestroy();
}
}
ScapegoatService :拥有和工作线程相同id,启动后立马自行停止并销毁,也就替ForegroundService 消除了通知。
package com.zyc.foregroundservice;
import android.app.Notification;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class ScapegoatService extends Service {
private static final int SERVICE_ID = 1; //后台ForegroundService的SERVICE_ID相同
public ScapegoatService() {
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.d(MainActivity.TAG, “创建前台服务替身”);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startForeground(SERVICE_ID, new Notification());
stopForeground(true);//移除通知栏消息
stopSelf();
return START_STICKY;
}
@Override
public void onDestroy() {
Log.d(MainActivity.TAG, “销毁前台服务替身”);
super.onDestroy();
}
}
MainActivity :启动/停止Service而已,不多赘述。
package com.zyc.foregroundservice;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
public static String TAG = “MyLog”;
private Intent intent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent(this, ForegroundService.class);
startService(intent);
}
@Override
protected void onDestroy() {
stopService(intent);
super.onDestroy();
}
}
运行,在Android 5.1.1下可以以此消除通知栏Service提示。
[图片上传失败…(image-3f45a3-1603077932504)]
单进程广播守护
本方案主要是通过Service销毁发出广播通知BroadcastReceiver“复活”自己实现进程保活。
项目结构如下。
AndroidManifest.xml:
KeepAliveReceiver :为啥用BroadcastReceiver 而不直接在 Service的onDestroy()方法中重启服务?因为这种方式启动的Service仍旧和原进程"在一起",会被一并杀死,而BroadcastReceiver 接到广播启动的则与原进程有隔离性,可以存活。
package com.zyc.demo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class KeepAliveReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(MainActivity.LOG_TAG, “收到保活广播”);
if (!MainActivity.isServiceRunning(context.getApplicationContext(), KeepAliveService.class)) {
Log.d(MainActivity.LOG_TAG, “检测到服务未在运行,启动服务”);
Intent serviceIntent = new Intent(context, KeepAliveService.class);
context.startService(serviceIntent);
} else {
Log.d(MainActivity.LOG_TAG, “检测到服务正在运行,无需再次启动”);
}
}
}
KeepAliveService :该Service会在创建后会对变量count 执行 +1/秒 定时任务,在服务终止/创建时会保存/读取count ,以保证count 的状态不会丢失。保活手段体现在:
- onStartCommand()返回 START_STICKY,Service所在进程被杀死后系统会尝试再次启动,但具体启动时机由系统决定。
- onDestroy()方法发送出Broadcast,等KeepAliveReceiver 收到后来启动自己。
package com.zyc.demo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import java.util.Timer;
impor