单进程广播守护
本方案主要是通过Service销毁发出广播通知BroadcastReceiver“复活”自己实现进程保活。
项目结构
AndroidManifest.xml:
<receiver
android:name=".KeepAliveReceiver"
android:enabled="true"
android:exported="true" />
<service
android:name=".KeepAliveService"
android:enabled="true"
android:exported="true" />
KeepAliveReceiver :为啥用BroadcastReceiver 而不直接在 Service的onDestroy()方法中重启服务?因为这种方式启动的Service仍旧和原进程"在一起",会被一并杀死,而BroadcastReceiver 接到广播启动的则与原进程有隔离性,可以存活。
package com.dzdpencrypt.dzdp;
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.dzdpencrypt.dzdp;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import java.util.Timer;
import java.util.TimerTask;
public class KeepAliveService extends Service {
private Timer timer;
private TimerTask timerTask;
public static int count;
@Override
public void onCreate() {
Log.d(MainActivity.LOG_TAG, "服务创建了");
int save = SharedPreferenceTool.getInstance(getApplicationContext()).getInt("count", -1);
if (save == -1) {
this.count = 0;
Log.d(MainActivity.LOG_TAG, "count首次启动,从0开始计数");
} else {
this.count = save;
Log.d(MainActivity.LOG_TAG, "count从上次保存的 " + save + " 开始计数");
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startTask();
Log.d(MainActivity.LOG_TAG, "服务启动了");
return START_STICKY;
}
/**
* 开启定时任务,count每秒+1
*/
private void startTask() {
timer = new Timer();
timerTask = new TimerTask() {
@Override
public void run() {
Log.d(MainActivity.LOG_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.LOG_TAG, "服务停止了");
Intent intent = new Intent(this, KeepAliveReceiver.class);
sendBroadcast(intent);
Log.d(MainActivity.LOG_TAG, "发送保活广播");
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
MainActivity :主要用于开启Service,并提供了判断指定Service是否运行的工具方法。count放在MainActivity 而不是Service是因为Service的onDestroy()在异常结束时不一定被调用。
package com.dzdpencrypt.dzdp;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
public static String LOG_TAG = "MyLog";
private Intent serviceIntent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (!isServiceRunning(getApplicationContext(), KeepAliveService.class)) {
Log.d(LOG_TAG, "检测到服务未在运行,启动服务");
serviceIntent = new Intent(this, KeepAliveService.class);
startService(serviceIntent);
} else {
Log.d(LOG_TAG, "检测到服务正在运行,无需再次启动");
}
}
/**
* 判断某个Service是否在运行
* @param context
* @param serviceClass 需要查看的Service的Class
* @return
*/
public static boolean isServiceRunning(Context context, Class serviceClass) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo runningServiceInfo : activityManager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(runningServiceInfo.service.getClassName())) {
return true;
}
}
return false;
}
@Override
protected void onDestroy() {
if (serviceIntent != null) {
stopService(serviceIntent);
}
SharedPreferenceTool.getInstance(getApplicationContext()).putInt("count", KeepAliveService.count);
Log.d(LOG_TAG, "count保存了");
super.onDestroy();
}
}
参考文章链接:
https://blog.youkuaiyun.com/zyc3545/article/details/109150010