参考资料:
https://blog.youkuaiyun.com/o279642707/article/details/82352431
https://blog.youkuaiyun.com/o279642707/article/details/82352431
https://www.cnblogs.com/Jhon-Mr/p/7699899.html
https://developer.android.google.cn/guide/topics/ui/notifiers/notifications#ManageChannels
1.来源
1.在开始之前,先了解一下前后台服务的区别:
这里借用一张图:
类别 | 区别 | 应用 |
前台服务 | 会在通知一栏显示 ONGOING 的 Notification, 当服务被终止的时候,通知一栏的 Notification 也会消失,这样对于用户有一定的通知作用。 | 音乐播放 |
后台服务 | 默认的服务即为后台服务,即不会在通知一栏显示 ONGOING 的 Notification。 当服务被终止的时候,用户是看不到效果的。 | 监控进程,可以是天气监控,系统状态监控等等 |
2.谷歌在andorid 8.0提出了一个行为变更:当您的应用进入已缓存状态时,如果没有活动的组件,系统将解除应用具有的所有唤醒锁。此外,为提高设备性能,系统会限制未在前台运行的应用的某些行为。
具体而言:
* 现在,在后台运行的应用对后台服务的访问受到限制。
* 应用无法使用其清单注册大部分隐式广播(即,并非专门针对此应用的广播)。
默认情况下,这些限制仅适用于针对 O 的应用。不过,用户可以从 Settings 屏幕为任意应用启用这些限制,即使应用并不是以 O 为目标平台。
对于我这样的api coder而言,最实际的是以下部分
Android 8.0 还对特定函数做出了以下变更:
* 如果针对 Android 8.0 的应用尝试在不允许其创建后台服务的情况下使用 startService() 函数,则该函数将引发一个 IllegalStateException。
* 新的 Context.startForegroundService() 函数将启动一个前台服务。现在,即使应用在后台运行,系统也允许其调用 Context.startForegroundService()。不过,应用必须在创建服务后的五秒内调用该服务的 startForeground() 函数。
3.除了前台服务的限制,谷歌还设置一个叫做通知渠道的限制。
顾名思义:通知渠道就是通知的方法。在8.0(api26)之后,所有的通知必须通过自定义的通知渠道显示。用户可以基于这个基础对所有的通知进行更细化的控制。
因为前台服务需要显示通知,所以在启动服务的同时,需要去创建(如果没有)通知渠道,如果没有通知渠道,那么服务将无法运行。总之,在android 8.0 谷歌对后台服务做出了非常多的限制,比如进程保活,双开后台进程的方法在8.0无法用以前的思路完成了(╯‵□′)╯︵┻━┻。
2.android 8.0 启动服务
启动服务的代码:
start_service.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(MainActivity.this, ZTestService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent);
//8.0之后只允许使用如上方式启动服务(一定是前台)
}else{
startService(intent);
}
}
});
接下来就是最重要的部分,服务的代码:
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Build;
import android.os.IBinder;
import android.support.annotation.RequiresApi;
import android.util.Log;
import com.example.zhangzihao.testbig.R;
public class ZTestService extends Service {
private final String TAG = "test";
private static final String CHANNEL_ID = "myService";
//创建服务时调用
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onCreate() {
super.onCreate();
//设置通知渠道
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationChannel Channel = new NotificationChannel(CHANNEL_ID, "主服务", NotificationManager.IMPORTANCE_HIGH);
Channel.enableLights(true);//设置提示灯
Channel.setLightColor(Color.GREEN);//设置提示灯颜色
Channel.setShowBadge(true);//显示logo
Channel.setDescription("你好啊");//设置描述
Channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
//设置锁屏可见 VISIBILITY_PUBLIC=可见
if (manager != null) {
manager.createNotificationChannel(Channel);
}
Notification notification = new Notification.Builder(this)
.setChannelId(CHANNEL_ID)
.setContentTitle("主服务")//标题
.setContentText("运行中...")//内容
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)//小图标一定需要设置,否则会报错(如果不设置它启动服务前台化不会报错,但是你会发现这个通知不会启动),如果是普通通知,不设置必然报错
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
.build();
//如果不设置startForeground方法,那么5秒之后就会报错
startForeground(1, notification);
//服务前台化只能使用startForeground()方法
// ,不能使用 notificationManager.notify(1,notification)
}
//服务执行的操作
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
//销毁服务时调用
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy");
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
注意点:
- 只能使用startForegroundService.
- 启动服务前台化通知的方法是startForeground(),如果使用notificationManager.notify(),将不会关联你启动的服务,系统会将它作为一个普通通知处理
那么8.0及其以上是只能启动前台服务了吗?
笔者找了部分博客,下面这个可以作为启动后台服务的一个参考,不过这并不是Google所推崇的,如果可以还是尽量使用前台服务。
https://blog.youkuaiyun.com/c1392851600/article/details/79659582