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

Android模拟器中SpeechRecognizer无法使用的问题求助

问题描述

我是Android应用开发新手,正在使用Kotlin开发语音助手。尝试调用麦克风时发现SpeechRecognizer无法工作,已按照指定视频教程操作,也尝试过GitHub上的相关解决方案,但在模拟器中测试时始终提示SpeechRecognizer不可用,SpeechRecognizer.isRecognitionAvailable始终返回不可用状态。

已尝试以下操作:

  • 在应用设置中添加所有权限
  • 在模拟器设置中启用麦克风

代码文件

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.firstkotlinproject">
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    <uses-permission android:name="android.speech.RecognitionService"/>

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.FirstKotlinProject"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:background="#525252">

    <TextView
        android:id="@+id/textView_to_change"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#FFA500"
        android:textSize="24sp"
        android:text="Hello"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button_to_click"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/textView_to_change"
        android:textColor="#FFA500"
        android:backgroundTint="#000"/>

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity.kt

package com.example.firstkotlinproject

import android.app.Activity
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.speech.RecognizerIntent
import android.speech.SpeechRecognizer
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*
import java.util.*
import kotlin.collections.ArrayList

class MainActivity : AppCompatActivity() {
    private val requestCodeDefoult = 102
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        button_to_click.setOnClickListener {
            askSpeechInput()
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == requestCodeDefoult && resultCode == Activity.RESULT_OK) {
            val result :ArrayList<String>? = data?.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)
            textView_to_change.text = result?.get(0).toString()
        }
    }
    private fun buttonPressed() :Boolean {
        var result = false
        if (button_to_click.isPressed) {
            result = true
        }
        return result
    }

    private fun askSpeechInput() {
        if (!SpeechRecognizer.isRecognitionAvailable(this)) {
            Toast.makeText(this, "Speech recognition is not avaiable!", Toast.LENGTH_SHORT).show()
        } else if (!buttonPressed()) {
            Toast.makeText(this, "Press the button to speak", Toast.LENGTH_SHORT).show()
        } else {
            val i = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
            i.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
            i.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.ITALIAN)
            i.putExtra(RecognizerIntent.EXTRA_PROMPT, "Say something...")
            startActivity(i)
        }
    }
}
解决方案

1. 解决模拟器语音识别服务缺失问题

大部分默认Android模拟器(不带Google服务的版本)没有预装语音识别核心服务,导致SpeechRecognizer.isRecognitionAvailable直接返回false。两种解决方式:

  • 创建AVD时选择带Google APIs的系统镜像(比如Android 13+的Google APIs x86_64版本)
  • 直接用物理设备测试:物理设备基本都预装了语音识别服务,结果更准确

2. 补全动态权限申请

RECORD_AUDIO属于危险权限,仅在Manifest声明不够,必须动态申请。修改MainActivity代码:

private val RECORD_AUDIO_PERMISSION_REQUEST_CODE = 100

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    
    // 检查并申请录音权限
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.RECORD_AUDIO), RECORD_AUDIO_PERMISSION_REQUEST_CODE)
    }
    
    button_to_click.setOnClickListener {
        askSpeechInput()
    }
}

override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    if (requestCode == RECORD_AUDIO_PERMISSION_REQUEST_CODE) {
        if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            Toast.makeText(this, "权限已授予", Toast.LENGTH_SHORT).show()
        } else {
            Toast.makeText(this, "需要录音权限才能使用语音识别", Toast.LENGTH_SHORT).show()
        }
    }
}

需要补充的import:

import android.Manifest
import android.content.pm.PackageManager
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat

3. 修复代码逻辑错误

  • buttonPressed()判断无效:点击事件触发后,按钮的isPressed状态已经恢复,导致永远进入"Press the button to speak"分支,直接删除该判断。
  • 替换startActivity()为startActivityForResult():原来的调用不会触发onActivityResult回调,修改后才能接收识别结果。

修改后的askSpeechInput():

private fun askSpeechInput() {
    if (!SpeechRecognizer.isRecognitionAvailable(this)) {
        Toast.makeText(this, "语音识别不可用!", Toast.LENGTH_SHORT).show()
    } else {
        // 再次检查权限
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.RECORD_AUDIO), RECORD_AUDIO_PERMISSION_REQUEST_CODE)
            return
        }
        val i = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
        i.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM)
        i.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.ITALIAN)
        i.putExtra(RecognizerIntent.EXTRA_PROMPT, "请说话...")
        startActivityForResult(i, requestCodeDefoult)
    }
}

4. 移除无用权限

android.speech.RecognitionService是服务声明权限,不是应用需要申请的权限,从AndroidManifest.xml中删除这一行:

<uses-permission android:name="android.speech.RecognitionService"/>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 15:36:20