android studio startforeground,service - 升级到Android 8.1后startForeground失败

service - 升级到Android 8.1后startForeground失败

将手机升级到8.1开发人员预览后,我的后台服务不再正常启动。

在我长期运行的服务中,我实现了一个startForeground方法来启动在create上调用的持续通知。

@TargetApi(Build.VERSION_CODES.O)

private fun startForeground() {

// Safe call, handled by compat lib.

val notificationBuilder = NotificationCompat.Builder(this, DEFAULT_CHANNEL_ID)

val notification = notificationBuilder.setOngoing(true)

.setSmallIcon(R.drawable.ic_launcher_foreground)

.build()

startForeground(101, notification)

}

错误信息:

11-28 11:47:53.349 24704-24704/$PACKAGE_NAMEE/AndroidRuntime: FATAL EXCEPTION: main

Process: $PACKAGE_NAME, PID: 24704

android.app.RemoteServiceException: Bad notification for startForeground: java.lang.RuntimeException: invalid channel for service notification: Notification(channel=My channel pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x42 color=0x00000000 vis=PRIVATE)

at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1768)

at android.os.Handler.dispatchMessage(Handler.java:106)

at android.os.Looper.loop(Looper.java:164)

at android.app.ActivityThread.main(ActivityThread.java:6494)

at java.lang.reflect.Method.invoke(Native Method)

at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)

at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

服务通知的通道无效,显然我的旧通道DEFAULT_CHANNEL_ID不再适用于我假设的API 27。 什么是合适的渠道? 我试图浏览一下文档

7个解决方案

142 votes

经过一些修补不同的解决方案后,您似乎必须在8.1中创建自己的通知渠道。

private fun startForeground() {

val channelId =

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

createNotificationChannel("my_service", "My Background Service")

} else {

// If earlier version channel ID is not used

// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)

""

}

val notificationBuilder = NotificationCompat.Builder(this, channelId )

val notification = notificationBuilder.setOngoing(true)

.setSmallIcon(R.mipmap.ic_launcher)

.setPriority(PRIORITY_MIN)

.setCategory(Notification.CATEGORY_SERVICE)

.build()

startForeground(101, notification)

}

@RequiresApi(Build.VERSION_CODES.O)

private fun createNotificationChannel(channelId: String, channelName: String): String{

val chan = NotificationChannel(channelId,

channelName, NotificationManager.IMPORTANCE_NONE)

chan.lightColor = Color.BLUE

chan.lockscreenVisibility = Notification.VISIBILITY_PRIVATE

val service = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

service.createNotificationChannel(chan)

return channelId

}

根据我的理解,后台服务现在显示为正常通知,然后用户可以通过取消选择通知通道来选择不显示。

更新:另外不要忘记根据需要添加前台权限Android P:

Rawa answered 2019-06-25T06:05:12Z

64 votes

Java解决方案(Android 9.0,API 28)

在您的AndroidManifest.xml课程中,添加以下内容:

@Override

public void onCreate(){

super.onCreate();

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)

startMyOwnForeground();

else

startForeground(1, new Notification());

}

private void startMyOwnForeground(){

String NOTIFICATION_CHANNEL_ID = "com.example.simpleapp";

String channelName = "My Background Service";

NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE);

chan.setLightColor(Color.BLUE);

chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);

NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

assert manager != null;

manager.createNotificationChannel(chan);

NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);

Notification notification = notificationBuilder.setOngoing(true)

.setSmallIcon(R.drawable.icon_1)

.setContentTitle("App is running in background")

.setPriority(NotificationManager.IMPORTANCE_MIN)

.setCategory(Notification.CATEGORY_SERVICE)

.build();

startForeground(2, notification);

}

更新:ANDROID 9.0 PIE(API 28)

将此权限添加到您的AndroidManifest.xml文件中:

CopsOnRoad answered 2019-06-25T06:05:59Z

16 votes

第一个答案非常适合那些了解kotlin的人,对于那些仍在使用java的人,我翻译了第一个答案

public Notification getNotification() {

String channel;

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)

channel = createChannel();

else {

channel = "";

}

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, channel).setSmallIcon(android.R.drawable.ic_menu_mylocation).setContentTitle("snap map fake location");

Notification notification = mBuilder

.setPriority(PRIORITY_LOW)

.setCategory(Notification.CATEGORY_SERVICE)

.build();

return notification;

}

@NonNull

@TargetApi(26)

private synchronized String createChannel() {

NotificationManager mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);

String name = "snap map fake location ";

int importance = NotificationManager.IMPORTANCE_LOW;

NotificationChannel mChannel = new NotificationChannel("snap map channel", name, importance);

mChannel.enableLights(true);

mChannel.setLightColor(Color.BLUE);

if (mNotificationManager != null) {

mNotificationManager.createNotificationChannel(mChannel);

} else {

stopSelf();

}

return "snap map channel";

}

对于Android,P不要忘记包含此权限

Hamza answered 2019-06-25T06:06:32Z

15 votes

在Android 8.1上正常运行:

更新了示例(没有任何弃用的代码):

public NotificationBattery(Context context) {

this.mCtx = context;

mBuilder = new NotificationCompat.Builder(context, CHANNEL_ID)

.setContentTitle(context.getString(R.string.notification_title_battery))

.setSmallIcon(R.drawable.ic_launcher)

.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)

.setChannelId(CHANNEL_ID)

.setOnlyAlertOnce(true)

.setPriority(NotificationCompat.PRIORITY_MAX)

.setWhen(System.currentTimeMillis() + 500)

.setGroup(GROUP)

.setOngoing(true);

mRemoteViews = new RemoteViews(context.getPackageName(), R.layout.notification_view_battery);

initBatteryNotificationIntent();

mBuilder.setContent(mRemoteViews);

mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

if (AesPrefs.getBooleanRes(R.string.SHOW_BATTERY_NOTIFICATION, true)) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

NotificationChannel channel = new NotificationChannel(CHANNEL_ID, context.getString(R.string.notification_title_battery),

NotificationManager.IMPORTANCE_DEFAULT);

channel.setShowBadge(false);

channel.setSound(null, null);

mNotificationManager.createNotificationChannel(channel);

}

} else {

mNotificationManager.cancel(Const.NOTIFICATION_CLIPBOARD);

}

}

老剪断(这是一个不同的应用程序 - 与上面的代码无关):

@Override

public int onStartCommand(Intent intent, int flags, final int startId) {

Log.d(TAG, "onStartCommand");

String CHANNEL_ONE_ID = "com.kjtech.app.N1";

String CHANNEL_ONE_NAME = "Channel One";

NotificationChannel notificationChannel = null;

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {

notificationChannel = new NotificationChannel(CHANNEL_ONE_ID,

CHANNEL_ONE_NAME, IMPORTANCE_HIGH);

notificationChannel.enableLights(true);

notificationChannel.setLightColor(Color.RED);

notificationChannel.setShowBadge(true);

notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);

NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

manager.createNotificationChannel(notificationChannel);

}

Bitmap icon = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);

Notification notification = new Notification.Builder(getApplicationContext())

.setChannelId(CHANNEL_ONE_ID)

.setContentTitle(getString(R.string.obd_service_notification_title))

.setContentText(getString(R.string.service_notification_content))

.setSmallIcon(R.mipmap.ic_launcher)

.setLargeIcon(icon)

.build();

Intent notificationIntent = new Intent(getApplicationContext(), MainActivity.class);

notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);

notification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, 0);

startForeground(START_FOREGROUND_ID, notification);

return START_STICKY;

}

Martin Pfeffer answered 2019-06-25T06:07:12Z

4 votes

在我的情况下,这是因为我们试图在不指定channelId的情况下发布通知:

public static final String NOTIFICATION_CHANNEL_ID_SERVICE = "com.mypackage.service";

public static final String NOTIFICATION_CHANNEL_ID_TASK = "com.mypackage.download_info";

public void initChannel(){

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

nm.createNotificationChannel(new NotificationChannel(NOTIFICATION_CHANNEL_ID_SERVICE, "App Service", NotificationManager.IMPORTANCE_DEFAULT));

nm.createNotificationChannel(new NotificationChannel(NOTIFICATION_CHANNEL_ID_INFO, "Download Info", NotificationManager.IMPORTANCE_DEFAULT));

}

}

上面代码的最佳位置是Application类中的channelId方法,因此我们只需要为所有方法声明一次:

public class App extends Application {

@Override

public void onCreate() {

super.onCreate();

initChannel();

}

}

在我们设置之后,我们可以使用我们刚刚指定的channelId的通知:

Intent i = new Intent(this, MainActivity.class);

i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);

PendingIntent pi = PendingIntent.getActivity(this, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID_INFO);

.setContentIntent(pi)

.setWhen(System.currentTimeMillis())

.setContentTitle("VirtualBox.exe")

.setContentText("Download completed")

.setSmallIcon(R.mipmap.ic_launcher);

然后,我们可以使用它发布通知:

int notifId = 45;

NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

nm.notify(notifId, builder.build());

如果要将其用作前台服务通知:

startForeground(notifId, builder.build());

Anggrayudi H answered 2019-06-25T06:08:09Z

1 votes

这对我有用。 在我的服务类中,我为android 8.1创建了通知通道,如下所示:

public class Service extends Service {

public static final String NOTIFICATION_CHANNEL_ID_SERVICE = "com.package.MyService";

public static final String NOTIFICATION_CHANNEL_ID_INFO = "com.package.download_info";

@Override

public void onCreate() {

super.onCreate();

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

nm.createNotificationChannel(new NotificationChannel(NOTIFICATION_CHANNEL_ID_SERVICE, "App Service", NotificationManager.IMPORTANCE_DEFAULT));

nm.createNotificationChannel(new NotificationChannel(NOTIFICATION_CHANNEL_ID_INFO, "Download Info", NotificationManager.IMPORTANCE_DEFAULT));

} else {

Notification notification = new Notification();

startForeground(1, notification);

}

}

}

注意:创建用于创建Build.VERSION.SDK_INT >= Build.VERSION_CODES.O通知的通道

Arjun answered 2019-06-25T06:08:42Z

1 votes

感谢@CopsOnRoad,他的解决方案是一个很大的帮助,但只适用于SDK26岁及以上。 我的应用针对24岁及以上。

为了防止Android Studio抱怨,您需要直接围绕通知提供条件。 知道代码是在一个以VERSION_CODE.O为条件的方法中是不够聪明的。

~~~    @覆盖     public void onCreate(){        super.onCreate();         if(Build.VERSION.SDK_INT> = Build.VERSION_CODES.O)            startMyOwnForeground();         其他             startForeground(1,new Notification());    }

private void startMyOwnForeground(){

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){

String NOTIFICATION_CHANNEL_ID = "com.example.simpleapp";

String channelName = "My Background Service";

NotificationChannel chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE);

chan.setLightColor(Color.BLUE);

chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);

NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

assert manager != null;

manager.createNotificationChannel(chan);

NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);

Notification notification = notificationBuilder.setOngoing(true)

.setSmallIcon(AppSpecific.SMALL_ICON)

.setContentTitle("App is running in background")

.setPriority(NotificationManager.IMPORTANCE_MIN)

.setCategory(Notification.CATEGORY_SERVICE)

.build();

startForeground(2, notification);

}

}

~~~

MobileMateo answered 2019-06-25T06:09:26Z

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值