You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用stopService()后Foreground Service仍持续运行的问题排查

Foreground Service 停止问题排查

我查阅Android官方文档关于Foreground Service的说明:

调用stopForeground()可将服务移出前台,该方法的布尔参数控制是否移除状态栏通知,但服务会继续运行;若在前台运行时停止服务,仅通知会被移除。

这是否意味着无法完全停止服务,需由系统处理?还是需要手动操作?我调用stopService(intent)方法停止服务,但通知移除后服务仍在运行。

Logcat中出现警告:

W/System: A resource failed to call close. 该信息无法提供足够排障线索。


我的Service实现代码

public class MyService extends Service {
    RemoteViews custom;
    NotificationManager notificationmanager;
    Notification notification;
    IBinder mBinder = new MyBinder();
   
    @Override
    public void onCreate() {
        super.onCreate();
        notificationmanager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
        Notification_Channel(this);
        startForeground(2,Show_notification(this));
    }

    public class MyBinder extends Binder {
        MyService getService() {
            return MyService.this;
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

   
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        String  action = intent.getAction();
        if(action!=null) {
            switch (action) {
                case "stop":
                    stopService(intent);
                    stopSelf();
                    break;
            }
        }
        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @RequiresApi(api = Build.VERSION_CODES.S)
    public void Notification_Channel (Context context) {
        //creating channel
        String offerchannelname = "...";
        String offerchanneldescription = "...";
        int offerchannel_importance = NotificationManager.IMPORTANCE_LOW;
        NotificationChannel notifchannel = new NotificationChannel( offerchannelid, offerchannelname,offerchannel_importance);
        notifchannel.setDescription(offerchanneldescription);
        // disable sound
        notifchannel.setSound(null,null);
        notificationmanager.createNotificationChannel(notifchannel);

        // using custom Layout
        custom = new RemoteViews(context.getPackageName(),R.layout.audio_player_notification);
        Show_notification(context);
    }

    @RequiresApi(api = Build.VERSION_CODES.S)
    public Notification Show_notification(Context context) {
        PendingIntent pendingIntent;

        Intent clickIntent = new Intent("action1");
        pendingIntent = PendingIntent.getBroadcast(context,3, clickIntent, PendingIntent.FLAG_IMMUTABLE| PendingIntent.FLAG_UPDATE_CURRENT);
        custom.setOnClickPendingIntent(R.id.MyId,pendingIntent);

        Intent clickIntent2 = new Intent("action2");
        pendingIntent = PendingIntent.getBroadcast(context,4, clickIntent2,PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
        custom.setOnClickPendingIntent(R.id.myId_player,pendingIntent);

        Intent clickIntent3 = new Intent("action3");
        pendingIntent = PendingIntent.getBroadcast(context,5, clickIntent3,PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);
        custom.setOnClickPendingIntent(R.id.myid,pendingIntent);

        Intent open_intent = new Intent(context,Main_Page.class);
        open_intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        pendingIntent= PendingIntent.getActivity(context.getApplicationContext(),0,open_intent,PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT);

        return  notification=new NotificationCompat.Builder(context,channel_id)
                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
                .setOngoing(true)
                .setContentIntent(pendingIntent)
                .setStyle(new NotificationCompat.DecoratedCustomViewStyle())
                .setCustomContentView(custom)
                .setSmallIcon(R.drawable.ic_launcher_foreground)
                .build();
    }
}

启动服务的代码

Intent service_intent = new Intent(context,MyService.class);
ContextCompat.startForegroundService(context,service_intent);
context.bindService(service_intent, this,Context.BIND_AUTO_CREATE);

停止服务的代码

Intent service_intent = new Intent(context,MyService.class);
service_intent.setAction("stop");
ContextCompat.startForegroundService(context,service_intent);
context.unbindService(service_intent,this);

问题原因与修复方案

核心问题

  1. 绑定未正确解除:启动服务时同时调用了bindService,绑定服务会让服务生命周期与绑定组件绑定,仅调用stopService/stopSelf无法终止服务,必须先解绑。
  2. 停止逻辑错误:onStartCommand中调用stopService(intent)无效,且未先移除前台状态;停止服务时调用startForegroundService属于多余操作。
  3. 解绑方式错误:unbindService需要传入绑定用的ServiceConnection实例,而非Intent,当前代码会导致解绑失败。

修复步骤

1. 修正Service内的停止逻辑

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    String action = intent.getAction();
    if(action!=null) {
        switch (action) {
            case "stop":
                // 先移除前台状态和通知
                stopForeground(true);
                // 停止服务
                stopSelf();
                break;
        }
    }
    return START_NOT_STICKY;
}

2. 正确解除绑定

绑定服务时保存ServiceConnection实例:

// 在Activity中定义
private ServiceConnection serviceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        // 处理绑定逻辑
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
    }
};

停止时正确解绑:

try {
    context.unbindService(serviceConnection);
} catch (IllegalArgumentException e) {
    // 避免未绑定时报错
    e.printStackTrace();
}

3. 调整停止服务的代码

// 先解绑
try {
    context.unbindService(serviceConnection);
} catch (IllegalArgumentException e) {
    e.printStackTrace();
}
// 直接停止服务
Intent stopIntent = new Intent(context, MyService.class);
context.stopService(stopIntent);

4. 完善资源清理

在onDestroy中清理资源,解决resource failed to call close警告:

@Override
public void onDestroy() {
    super.onDestroy();
    custom = null;
    if (notificationmanager != null) {
        notificationmanager.cancelAll();
        notificationmanager = null;
    }
}

关键知识点

  • Foreground Service完全停止需要解除所有绑定 + 调用停止方法(stopService/stopSelf)。
  • stopForeground(true)仅移除前台状态和通知,服务仍在运行,必须手动停止。
  • 绑定服务后,只有所有绑定解除且无待处理启动命令时,onDestroy才会触发。

内容的提问来源于stack exchange,提问作者A.G

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 11:36:29