You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

多Activity应用中用户返回主屏幕时停止IntentService的实现

解决思路与实现方案

首先得提醒你:IntentService并不适合持续运行的场景——它的设计初衷是异步处理一次性任务,任务完成后会自动停止。所以要实现持续的关键词识别,你需要把它换成普通的Service,这样才能长时间保持运行状态。

接下来核心问题是如何监听应用的前后台状态,从而控制服务的启停。这里有两种可靠的实现方式:

方式一:使用ProcessLifecycleOwner(推荐)

这是AndroidX提供的官方方案,能精准监听整个应用的生命周期状态,代码更简洁且不易出错。

步骤1:添加依赖

在你的app/build.gradle里引入生命周期组件库:

implementation "androidx.lifecycle:lifecycle-process:2.6.2"

步骤2:自定义Application类监听前后台

创建一个继承自Application的类,注册生命周期观察者:

public class MyApp extends Application implements LifecycleObserver {

    @Override
    public void onCreate() {
        super.onCreate();
        // 注册应用生命周期观察者
        ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
    }

    // 应用进入前台时触发
    @OnLifecycleEvent(Lifecycle.Event.ON_START)
    public void onAppEnterForeground() {
        // 启动关键词识别服务
        startService(new Intent(this, KeywordRecognitionService.class));
    }

    // 应用完全进入后台时触发(所有Activity都已暂停)
    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    public void onAppEnterBackground() {
        // 停止服务,释放麦克风资源
        stopService(new Intent(this, KeywordRecognitionService.class));
    }
}

别忘了在AndroidManifest.xml里声明这个Application:

<application
    android:name=".MyApp"
    ...>
    <!-- 其他配置 -->
</application>

方式二:基于Activity计数的传统方案

如果你的项目还没迁移到AndroidX,或者更习惯用传统方式,可以通过基类Activity维护一个计数器来判断应用是否在前台。

步骤1:创建BaseActivity

让所有业务Activity都继承这个基类:

public abstract class BaseActivity extends AppCompatActivity {
    // 记录当前处于前台的Activity数量
    private static int foregroundActivityCount = 0;

    @Override
    protected void onResume() {
        super.onResume();
        foregroundActivityCount++;
        // 从后台回到前台时启动服务
        if (foregroundActivityCount == 1) {
            startService(new Intent(this, KeywordRecognitionService.class));
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        foregroundActivityCount--;
        // 所有Activity都进入后台时停止服务
        if (foregroundActivityCount == 0) {
            stopService(new Intent(this, KeywordRecognitionService.class));
        }
    }
}

实现关键词识别服务

现在编写核心的KeywordRecognitionService,实现持续监听并在销毁时释放资源:

public class KeywordRecognitionService extends Service {
    private SpeechRecognizer speechRecognizer;
    private Intent recognizerIntent;
    private boolean isListening = false;

    @Override
    public void onCreate() {
        super.onCreate();
        // 初始化语音识别组件
        speechRecognizer = SpeechRecognizer.createSpeechRecognizer(this);
        speechRecognizer.setRecognitionListener(new RecognitionListener() {
            @Override
            public void onReadyForSpeech(Bundle params) {}

            @Override
            public void onBeginningOfSpeech() {}

            @Override
            public void onRmsChanged(float rmsdB) {}

            @Override
            public void onBufferReceived(byte[] buffer) {}

            @Override
            public void onEndOfSpeech() {}

            @Override
            public void onError(int error) {
                // 识别出错后重启监听(避免意外停止)
                if (isListening) {
                    speechRecognizer.startListening(recognizerIntent);
                }
            }

            @Override
            public void onResults(Bundle results) {
                ArrayList<String> matches = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION);
                if (matches != null) {
                    for (String match : matches) {
                        // 检查是否包含目标关键词
                        if (match.contains("你的关键词")) {
                            // 触发业务逻辑,比如发送广播通知Activity
                            sendBroadcast(new Intent("KEYWORD_DETECTED_ACTION"));
                            break;
                        }
                    }
                }
                // 重启监听,实现持续识别
                if (isListening) {
                    speechRecognizer.startListening(recognizerIntent);
                }
            }

            @Override
            public void onPartialResults(Bundle partialResults) {}

            @Override
            public void onEvent(int eventType, Bundle params) {}
        });

        // 配置识别参数
        recognizerIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
        recognizerIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
        recognizerIntent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, getPackageName());
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 避免重复启动监听
        if (!isListening && speechRecognizer != null) {
            speechRecognizer.startListening(recognizerIntent);
            isListening = true;
        }
        // 服务被系统杀死后不自动重启(因为我们靠应用前后台状态控制)
        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // 释放麦克风等资源
        if (speechRecognizer != null) {
            speechRecognizer.stopListening();
            speechRecognizer.destroy();
            isListening = false;
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null; // 不需要绑定服务
    }
}

权限配置

最后别忘了申请麦克风权限:

  1. AndroidManifest.xml添加静态权限:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<service android:name=".KeywordRecognitionService" />
  1. 在主Activity中动态申请权限(Android 6.0+必需):
private static final int REQUEST_RECORD_AUDIO_PERMISSION = 1001;

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

    // 检查并申请麦克风权限
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO)
            != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.RECORD_AUDIO},
                REQUEST_RECORD_AUDIO_PERMISSION);
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == REQUEST_RECORD_AUDIO_PERMISSION) {
        if (grantResults.length == 0 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(this, "需要麦克风权限才能使用语音识别功能", Toast.LENGTH_SHORT).show();
        }
    }
}

这样配置后,只要你的应用有任意Activity处于前台,服务就会保持运行监听关键词;当用户返回设备主屏幕(应用完全进入后台),服务会自动停止并释放麦克风资源,完美符合你的需求。

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

火山引擎 最新活动