原文标题:Use Voice Search to integrate with Google Now

原文链接:http://antonioleiva.com/voice_search_google_now/

原文作者:Antonio Leiva(http://antonioleiva.com/about/

原文发布:2015-10-14

Android最棒的能力之一就是可以将我们的APP以不同的方式集成到它的生态链中。APP相互之间可以进行“交流”,这给予我们极大的灵活性来创建独特的应用体验。

集成Google应用就是一个典型的例子。有很多不同的特性可以帮助我们提升APP的知名度,如APP索引或一组强大的语音功能

语音搜索

尽管,在APP中实现语音搜索的过程与任何其他语音功能类似,但是,在这篇文章中,我还是会聚焦在怎样在APP中实现语音搜索功能。你也可以在Play Music中尝试这个例子:

  • 好,GooglePlay Music中,搜索Beatles

这句指令将在Play Music APP中开启搜索Beatles。

怎样实现语音搜索

当语音搜索启动后,我们的APP将收到一个查询文字的Intent,我们必须捕捉和分析这段文字。所以,这第一部分是指定哪个Activity接收这条Intent:

 <activity android:name=".MainActivity" android:launchMode="singleTask" >
<intent-filter>
<action android:name="com.google.android.gms.actions.SEARCH_ACTION"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>

这个动作(action)称为com.google.android.gms.actions.SEARCH_ACTION,所以我们说MainActivity是处理这类Intent。另外,我用singleTask启动模式,这样MainActivity就仅仅创建一次。否则,每次收到这条Intent就要创建一个新的Activity实例。

接下来的一步是要在MainActivity内进行处理它。当我们用singleTask模式时,在Activity的两个不同位置上可以接收Intent:首先是用getIntent()创建Activity,接着是onNewIntent方法中。这样就要创建一个处理方法在需要它的时候调用它:

     private static final String ACTION_VOICE_SEARCH = "com.google.android.gms.actions.SEARCH_ACTION";
  ...
private void handleVoiceSearch(Intent intent) {
if (intent != null && ACTION_VOICE_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
setSearchViewVisible(true);
searchView.setQuery(query, true);
}
}

这个方法检查Intent是否为空(null)或者是否是在收到查询文字前要检测的动作,它是Intent内部的额外动作。查询的额外动作关键字是SearchManager.QUERY。

在searchView后,设置查询,提交执行查询。其方法是onNewIntent:

 @Override protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
handleVoiceSearch(intent);
}

UI也准备好(在我们的例子中,当菜单弹出时,我们访问SearchView),你稍后将看到。

在我的例子中,UI是基于工具栏(Toolbar)内部的SearchView。你可以在前面的文章中看到怎样实现SearchView,不过我还是稍作解释怎样做。首先,产生菜单动作(menu action):

 <menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_search"
android:title="@string/action_search"
android:icon="@drawable/ic_search"
app:actionViewClass="android.support.v7.widget.SearchView"
app:showAsAction="ifRoom" />
</menu>

然后,在菜单弹出时,你请求SearchView:

 @Override public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu); MenuItem searchItem = menu.findItem(R.id.action_search);
searchView = (SearchView) MenuItemCompat.getActionView(searchItem); searchView.setOnSearchClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
setSearchViewVisible(true);
}
}); searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override public boolean onQueryTextSubmit(String query) {
Toast.makeText(MainActivity.this, query, Toast.LENGTH_LONG).show();
searchView.clearFocus();
return true;
} @Override public boolean onQueryTextChange(String newText) {
return false;
}
}); handleVoiceSearch(getIntent()); return true;
} private void setSearchViewVisible(boolean visible) { if (searchView.isIconified() == visible) {
searchView.setIconified(!visible);
} if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(visible);
}
}

怎样尝试

由于APP需要发布到Play商店中,Google Now才能检测到APP,所以我们还不能直接从Google Now尝试这个例子。但是,我们可以用ADB来调试它。这条命令是:

  • adb shell am start -a com.google.android.gms.actions.SEARCH_ACTION -e query searchquery app_package

对于从我的代码库下载的例子,就可以这样做:

  • adb shell am start -a com.google.android.gms.actions.SEARCH_ACTION -e query VoiceSearch com.antonioleiva.googlenowsearch

在APP完全关闭和启动时,都可以尝试本例了。这样,就可以测试两种可能的途径了。

附加说明:Kotlin语言的实现

你可能知道,因为我认为Kotlin语言可以非常好替代Java语言,Kotlin可以使我们的代码更简洁、可读性更好,所以这些天讨论了许多Kotlin语言的特性。作为例子,我将简化onCreateOptionsMenu,你可以在同一个代码库中找到完整的代码。

实现扩展函数的能力可以帮助我们减少冗长代码。例如,可以为Menu创建一个扩展函数,基于action id找到ActionView,返回层级视图:

 inline fun <reified T : View?> Menu.findCompatActionView(actionRes: Int): T {
val searchItem = findItem(actionRes)
return MenuItemCompat.getActionView(searchItem) as T
}

现在可以这样做:

 searchView = menu.findCompatActionView(R.id.action_search)

另一个扩展函数可以以清晰的方式帮助我们编写OueryTextListener:

 fun SearchView.onQueryText(submit: (String) -> Boolean = { false }, textChange: (String) -> Boolean = { false }) {

     this.setOnQueryTextListener(object : SearchView.OnQueryTextListener {

         override fun onQueryTextSubmit(query: String): Boolean = submit(query)

         override fun onQueryTextChange(newText: String): Boolean = textChange(newText)

     })
}

这个函数接收一对函数,一个用于侦听器中的每个方法,并给出它们的默认值。这样我们仅需要定义我们要用的。如果我们仅仅要第一个函数(对于第二个我们用默认的),现在我就可以这样做:

 searchView.onQueryText ({
longToast(it)
searchView.clearFocus()
true
})

最终,这个函数就是这样的:

 override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.main, menu) searchView = menu.findCompatActionView(R.id.action_search)
searchView.setOnSearchClickListener { setSearchViewVisible(true) } searchView.onQueryText ({
longToast(it)
searchView.clearFocus()
true
}) intent?.let { handleVoiceSearch(it) } return true
}

如你所见,如果在这个位置上(例如:在一个常规activity创建上),Intent可以为null,就必须在使用它之前检查它是否为null。用let函数,可以避免if条件的创建,在对象调用时不为null,就可只进入对象内部。

如果你对Kotlin有兴趣,可以搜索Kotlin文章,或购买我编写的《Android开发者的Kotlin》一书。

将语音搜索集成到Google Now中的更多相关文章

  1. BaiduSpeechDemo【百度语音SDK集成】(基于v3.0.7.3)

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 本Demo将百度语音SDK(其中一部分功能)和自定义的UI对话框封装到一个module中,便于后续的SDK版本更新以及调用. 本De ...

  2. BaiduSpeechDemo【百度语音SDK集成】(基于v3.0.8.1)

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 上一篇集成的是V3.0.7.3版本的SDK<BaiduSpeechDemo[百度语音SDK集成](基于v3.0.7.3)> ...

  3. Android语音搜索

    前言 在现有的软件的搜索框中基本上都会加上语音搜索的图标,以方便用户输入.我们xxxx的搜索框其实也可以借鉴这样的输入方式,提高用户体验.语音识别有3种方式实现①使用intent调用语音识别程序;②通 ...

  4. Google Chrome中的高性能网络 (三)

    使用预连接优化了TCP连接管理 已经预解析到了主机名,也有了由OmniBox和Chrome Predictor提供信号,预示着用户未来的操作.为什么再进一步连接到目标主机,在用户真正发起请求前完成TC ...

  5. 如何在Google Map中处理大量标记(ASP.NET)(转)

    如何在Google Map中处理大量标记(ASP.NET)(原创-翻译) Posted on 2010-07-29 22:04 Happy Coding 阅读(8827) 评论(8) 编辑 收藏 在你 ...

  6. 怎样用Google APIs和Google的应用系统进行集成(1)----Google APIs简介

    Google的应用系统提供了非常多的应用,比方 Google广告.Google 任务,Google 日历.Google blogger,Google Plus,Google 地图等等非常的多的应用,请 ...

  7. Excel与Google Sheets中实现线性规划求解

    很久没更新过APS系列文章了,这段时间项目工作确实非常紧,所以只能抽点时间学习一下运筹学的入门知识,算是为以后的APS项目积累点基础.看了一些运筹学的书(都是科普级别的)发现原来我目前面对的很多排产. ...

  8. Cordova与现有框架的结合,Cordova插件使用教程,Cordova自定义插件,框架集成Cordova,将Cordova集成到现有框架中

    一.框架集成cordova 将cordova集成到现有框架中 一般cordova工程是通过CMD命令来创建一个工程并添加Android.ios等平台,这样的创建方式可以完整的下载开发过程中所需要的的插 ...

  9. 多玩YY语音的面试题:C++中如何在main()函数之前执行操作?

    多玩YY语音的面试题:C++中如何在main()函数之前执行操作? 第一反应main()函数是所有函数执行的开始.但是问题是main()函数执行之前如何执行呢? 联想到MFC里面的 C**App类的t ...

随机推荐

  1. Dancing Links and Exact Cover

    1. Exact Cover Problem DLX是用来解决精确覆盖问题行之有效的算法. 在讲解DLX之前,我们先了解一下什么是精确覆盖问题(Exact Cover Problem)? 1.1 Po ...

  2. 项目游戏开发日记 No.0x000001

    14软二杨近星(2014551622) 既然已经决定了开发软件, 时不时就要练练手, 还要时不时的去寻找素材, 因为开发的人物设定就是DotA2里面的祈求者, 所以, 就去找了他的相关人物图片和模型, ...

  3. hasOwnProperty()、propertyIsEnumerable()和isPrototypeOf()的用法

    javascript中有原型这么一个概念,任何一个构造函数都有它对应的原型(prototype),我们可以给这个原型赋予一些我们想要的属性,像下面这样: function Gadget(name, c ...

  4. 40个Java多线程问题总结

    前言 Java多线程分类中写了21篇多线程的文章,21篇文章的内容很多,个人认为,学习,内容越多.越杂的知识,越需要进行深刻的总结,这样才能记忆深刻,将知识变成自己的.这篇文章主要是对多线程的问题进行 ...

  5. 转职成为TypeScript程序员的参考手册

    写在前面 作者并没有任何可以作为背书的履历来证明自己写作这份手册的分量. 其内容大都来自于TypeScript官方资料或者搜索引擎获得,期间掺杂少量作者的私见,并会标明. 大部分内容来自于http:/ ...

  6. 基于Quick-cocos2d-x的资源更新方案 二

    写在前面 又是12点半了,对于一个程序员来说,这是一个黄金时间,精力旺盛,我想,是最适合整理和分享一些思路的时候了. 自从上次写了 基于Quick-cocos2d-x的资源更新方案 同样可见quick ...

  7. CSharpGL(32)矩阵与四元数与角度旋转轴的相互转换

    CSharpGL(32)矩阵与四元数与角度旋转轴的相互转换 三维世界里的旋转(rotate),可以用一个3x3的矩阵描述:可以用(旋转角度float+旋转轴vec3)描述.数学家欧拉证明了这两种形式可 ...

  8. APP测试点总结(功能,交互,死机崩溃状态分析,容易出错的检查点)

    APP测试点总结(功能,交互,死机崩溃状态分析,容易出错的检查点) 版权声明:本文为博主原创文章,未经博主允许不得转载. 最近涉足APP端测试,常见检查点总结如下:   一.业务方面: 1.  注册( ...

  9. .net使用正则表达式校验、匹配字符工具类

    开发程序离不开数据的校验,这里整理了一些数据的校验.匹配的方法: /// <summary> /// 字符(串)验证.匹配工具类 /// </summary> public c ...

  10. python资料

    Python进阶 https://pythontips.com/ https://flyouting.gitbooks.io/learn-python-the-hard-way-cn/content/ ...