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

应用被强制关闭后Broadcast Receiver无法调用Service问题

兄弟,我看你在小米Redmi Note4上遇到了强制关闭应用后Service没法重启的问题,这事儿我太熟了——一方面是MIUI的后台管控太严,另一方面是你当前的代码有几个关键问题没处理到,咱们一步步来解决:

核心问题分析

先把根儿上的问题捋清楚:

  • 你用的是动态注册BroadcastReceiver,这种Receiver完全依赖应用进程存活,一旦应用被强制杀死,动态注册的Receiver就跟着失效了,根本接收不到广播,自然没法重启Service。
  • 小米MIUI有自己的后台管控机制,默认会限制非白名单应用的后台行为,哪怕代码写对了,没开权限也白搭。
  • Android 8.0(API 26)之后,系统对后台启动Service做了严格限制,直接用startService()会抛出异常,必须用前台服务的方式。
  • 当应用被强制关闭时,Service.onDestroy()大概率不会被调用,你在里面发的自定义广播根本发不出去,这个重启逻辑走不通。
分步解决方案

咱们先改代码,再配合系统设置,双管齐下:

1. 把BroadcastReceiver改成静态注册

动态注册靠不住,必须在AndroidManifest.xml里静态注册Receiver,这样即使应用进程被杀死,系统也能唤醒它(前提是权限够)。

修改AndroidManifest.xml,添加静态注册的Receiver和必要权限:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.turzo.servicetest">

    <!-- 前台服务权限 -->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <!-- 开机自启权限(可选,需要开机后自动重启Service就加) -->
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <!-- 网络状态权限(如果需要监听网络变化) -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <!-- 注册Service -->
        <service
            android:name=".SensorService"
            android:enabled="true"
            android:exported="false" />

        <!-- 静态注册重启Receiver -->
        <receiver
            android:name=".SensorRestarterBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <!-- 监听自定义重启广播 -->
            <intent-filter>
                <action android:name="com.turzo.servicetest.RestartSensor" />
                <!-- 可选:监听开机完成事件 -->
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
    </application>
</manifest>

2. 修改BroadcastReceiver适配Android O+

在Receiver里,Android O及以上版本不能直接调用startService(),必须用startForegroundService(),同时要处理版本兼容:

package com.turzo.servicetest;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.util.Log;

public class SensorRestarterBroadcastReceiver extends BroadcastReceiver {
    private static final String TAG = "RestartReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "收到重启Service的广播");
        Intent serviceIntent = new Intent(context, SensorService.class);
        
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // Android O及以上,启动前台服务
            context.startForegroundService(serviceIntent);
        } else {
            // 低版本直接启动
            context.startService(serviceIntent);
        }
    }
}

3. 把Service改成前台服务

为了避免被系统(尤其是MIUI)轻易杀死,把Service改成前台服务,在onStartCommand()里弹出一个低优先级的前台通知(尽量不打扰用户):

package com.turzo.servicetest;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
import java.util.Timer;
import java.util.TimerTask;

public class SensorService extends Service {
    private static final String TAG = "ServiceTest";
    private static final int NOTIFICATION_ID = 1001;
    private static final String CHANNEL_ID = "SensorServiceChannel";
    private Timer timer;
    private TimerTask timerTask;
    private int counter = 0;

    // 注意:Service只能有无参构造,系统创建Service时会调用这个,自定义带参构造会导致异常!
    public SensorService() {
        super();
        Log.i(TAG, "Service初始化");
    }

    @Override
    public void onCreate() {
        super.onCreate();
        // 创建通知渠道(Android O+必需)
        createNotificationChannel();
        // 启动前台服务
        startForeground(NOTIFICATION_ID, getNotification());
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);
        Log.i(TAG, "Service启动");
        startTimer();
        // 返回START_STICKY:如果Service被系统杀死,系统会尝试重启它(MIUI可能不严格遵守)
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "Service销毁");
        stoptimertask();
        // 发送自定义广播,尝试重启自己
        Intent broadcastIntent = new Intent("com.turzo.servicetest.RestartSensor");
        sendBroadcast(broadcastIntent);
    }

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

    // 创建通知渠道
    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    CHANNEL_ID,
                    "传感器服务",
                    NotificationManager.IMPORTANCE_LOW // 低优先级,不弹出通知
            );
            NotificationManager manager = getSystemService(NotificationManager.class);
            if (manager != null) {
                manager.createNotificationChannel(channel);
            }
        }
    }

    // 创建前台通知
    private Notification getNotification() {
        Notification.Builder builder;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            builder = new Notification.Builder(this, CHANNEL_ID);
        } else {
            builder = new Notification.Builder(this);
        }
        return builder.setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("传感器服务运行中")
                .setContentText("正在后台收集数据")
                .setPriority(Notification.PRIORITY_LOW)
                .build();
    }

    // 定时器相关代码
    private void startTimer() {
        timer = new Timer();
        initializeTimerTask();
        timer.schedule(timerTask, 1000, 1000);
    }

    private void initializeTimerTask() {
        timerTask = new TimerTask() {
            @Override
            public void run() {
                Log.i(TAG, "定时器运行中:" + (counter++));
            }
        };
    }

    private void stoptimertask() {
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
    }
}

4. 简化MainActivity,移除动态注册的Receiver

因为已经静态注册了Receiver,MainActivity里的动态注册可以去掉,避免重复注册:

package com.turzo.servicetest;

import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "ServiceTest";
    private Intent mServiceIntent;
    private Context ctx;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ctx = this;
        setContentView(R.layout.activity_main);

        mServiceIntent = new Intent(ctx, SensorService.class);
        if (!isMyServiceRunning(SensorService.class)) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                startForegroundService(mServiceIntent);
            } else {
                startService(mServiceIntent);
            }
        }
    }

    private boolean isMyServiceRunning(Class<?> serviceClass) {
        ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
            if (serviceClass.getName().equals(service.service.getClassName())) {
                Log.i(TAG, "Service正在运行");
                return true;
            }
        }
        Log.i(TAG, "Service未运行");
        return false;
    }

    @Override
    protected void onDestroy() {
        // 这里不要调用stopService,否则用户退出Activity就会停掉Service(如果你希望Service一直运行的话)
        // stopService(mServiceIntent);
        Log.i(TAG, "MainActivity销毁");
        super.onDestroy();
    }
}

5. 小米设备必须手动开启的权限

这一步是重中之重!MIUI默认会限制应用的后台行为,你必须手动开启:

  • 打开安全中心 → 应用管理 → 找到你的应用「ServiceTest」
  • 进入权限管理 → 开启「自启动」权限
  • 进入后台设置 → 选择「无限制」,禁止系统自动清理该应用的后台进程
  • (可选)如果还是不行,把应用加入省电优化的白名单,避免被省电策略杀死
补充说明

即使做了以上所有操作,MIUI的某些版本可能还是会在内存紧张时杀死后台服务,这是系统层面的限制,没法完全绕过,但前台服务+自启动权限已经是能做到的最优方案了。另外,不要过度依赖Service.onDestroy()发送广播,因为应用被强制关闭时这个方法可能不会执行,更好的方式是用系统广播(比如开机完成)或者WorkManager做周期性检查(Android Jetpack组件,更适合后台任务)。

内容的提问来源于stack exchange,提问作者XpressGeek

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:41:00