项目结构如下。
AndroidManifest.xml:
//不加该权限会报错:java.lang.SecurityException: Permission Denial: startForeground from pid=XXX, uid=XXX requires android.permission.FOREGROUND_SERVICE
…
ForegroundService :模拟工作的(前台)线程,如有必要会开启ScapegoatService来清除通知栏通知。由于缺乏更多高版本系统样本,Android 8.0以上部分可能不靠谱,不过推荐还是老老实实按谷歌要求发出通知为妙。
package com.zyc.foregroundservice;
import android.app.Notification;
import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.RequiresApi;
import java.util.Timer;
import java.util.TimerTask;
public class ForegroundService extends Service {
private static final int SERVICE_ID = 1;
private Timer timer;
private TimerTask timerTask;
public static int count;
public ForegroundService() {
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.d(MainActivity.TAG, “创建前台服务”);
}
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startTask();
//判断版本
if (Build.VERSION.SDK_INT < 18) {//Android4.3以下版本
//直接调用startForeground即可,不会在通知栏创建通知
startForeground(SERVICE_ID, new Notification());
} else if (Build.VERSION.SDK_INT < 24) {//Android4.3 - 7.0之间
Intent scapegoatIntent = new Intent(this, ScapegoatService.class);
startService(scapegoatIntent);
} else {//Android 8.0以上
//经测试,本人的一加6T(Android 10)这样写并不会在通知栏创建通知,其他机型与版本效果仍需考证
startForeground(SERVICE_ID, new Notification());
}
return START_STICKY;
}
/**
- 开启定时任务,count每秒+1
*/
private void startTask() {
timer = new Timer();
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 { <