1

This will be a self-answered question, because I'd like to clearly document how to determine if a search intent was triggered by text input or voice recognition. My reason for needing this was because I was trying to log searches in my app to Google Analytics, and I needed to know whether the user was typing their searches in on the keyboard as text, or if they were using the voice search feature.

I found a few questions on StackOverflow that addressed this question, but I found them to be hard to find and poorly documented. So hopefully my answer will provide the right keywords and details to help others find this topic more quickly and clearly in the future.

4

2 回答 2

0

Bundle[{android.speech.extra.RESULTS=[hello], query=hello, android.speech.extra.CONFIDENCE_SCORES=[0.9299549]}] 这将在语音包中

于 2020-06-08T00:38:13.543 回答
0

我的应用程序中的搜索活动正在singleTop模式下运行,因此我正在通过@Overrideof处理传入的搜索意图onNewIntent()。在此方法中,您需要做的第一件事是检查传入的意图是否实际上是搜索意图。我们通过以下方式完成此操作:

if (intent.getAction().equals(Intent.ACTION_SEARCH)){}

下一部分有点棘手,并导致我对旧 API 产生了一些误报。有两个附加到ACTION_SEARCH意图:QUERYUSER_QUERY. SearchManager如果我们在docs中阅读这两个值,我们会发现以下信息:

public static final String QUERY

意图额外数据键:使用此键 content.Intent.getStringExtra()来获取查询字符串 Intent.ACTION_SEARCH

public static final String USER_QUERY

Intent extra data key:使用这个key content.Intent.getStringExtra()来获取用户输入的查询字符串。如果意图是选择建议的结果,这可能与 QUERY 的值不同。在这种情况下,QUERY 将包含建议的 SUGGEST_COLUMN_QUERY 的值, 而 USER_QUERY 将包含用户键入的字符串

本质上,我们可以从这两个 doc 条目中收集到的值QUERY将始终包含搜索的实际值,而不管搜索是如何执行的。因此,无论用户是输入搜索内容、通过语音识别说出它还是选择了搜索建议,这都无关紧要——该字段将包含他们正在搜索的内容的原始字符串值。

另一方面,USER_QUERY可能为空,也可能不为空,具体取决于执行搜索的方式。如果用户使用文本输入他们的搜索,该字段将包含他们的搜索值。如果用户使用语音识别执行搜索,则此值为 null

这为我们提供了一种很好的(尽管在某种程度上是骇人听闻的)方法来确定用户是在搜索中键入文本还是使用了语音搜索功能。但这里是棘手的部分:正如您在上面的文档中看到的,建议使用getStringExtra()从意图中检索此值。这是不可靠的,因为 的值USER_QUERY实际上是 a SpannableString,而不是 a String。这可能会导致 a ClassCastException,因为如果您使用getStringExtra(),您会尝试将 a 强制转换SpannableString为 a String,这是行不通的。将自动为您捕获异常,但您可能会收到一个误报的空值作为结果,导致您的代码相信搜索是通过语音识别执行的,而实际上键入的文本值只是因为 ClassCastException 而丢失。

因此,解决方案是改为使用SpannableStringfrom USER_QUERY,并检查其是否为 null,这样您就不会触发 ClassCastException 和误报 null。但是你会注意到它Intent没有获取 SpannableStrings 的方法,但它确实有一个getCharSequenceExtra()方法。由于SpannableStringimplements CharSequence,我们可以简单地使用此方法来检索我们的 USER_QUERY SpannableString,并在退出时将其强制转换。所以我们会这样做:

SpannableString user_query_spannable = (SpannableString) intent.getCharSequenceExtra(SearchManager.USER_QUERY);

我们现在可以检查此值是否为空,以安全地确定用户是否输入了文本或以其他方式(例如语音识别)执行搜索。

把它们放在一起,我们最终会得到这样的结果:

@Override
protected void onNewIntent(Intent intent) {

    if (intent.getAction().equals(Intent.ACTION_SEARCH)) {

        SpannableString user_query_spannable = (SpannableString) intent.getCharSequenceExtra(SearchManager.USER_QUERY);

        //if this was a voice search
        if (user_query_spannable == null) {
            //Log, send Analytics hit, etc.
            //Then perform search as normal...
            performSearch(intent.getStringExtra(SearchManager.QUERY));

        } else {
            //Log, send Analytics hit, etc.
            //Then perform search as normal
            performSearch(intent.getStringExtra(SearchManager.QUERY));
        }
    } 
}

正如我之前提到的,对我来说,通过在 Google 和 StackOverflow 上的搜索很难找到这些信息,尤其是当官方 Android 文档提供了有关如何使用这些值的误导性信息时。希望这个答案将为寻找类似信息的其他人提供更容易访问的资源。

于 2016-04-25T16:40:44.207 回答