简介
本文中将向你展示一个基本的Android应用程序,此程序能够聆听用户的声音并把它转换为文本数据。而且,此程序还能够进行文本分析,然后执行相应的命令来实现数据存储及用户应答功能。
注意,本文源码工程下载地址是:https://github.com/sitepoint-editors/SpeechApplication。
程序快照如下:
创建应用程序
打开Android Studio创建一个新的项目,选择最小版本的Android API 18并添加一个空的Activity。这也是本项目中唯一的一个Activity。
为了实现视图的全屏显示,打开配置文件AndroidManifest.xml,并设置如下:
- android:theme="@style/Theme.AppCompat.NoActionBar"
这个配置将使我们当前的活动(Activity)中隐藏ActionBar的显示。
到此,你已经拥有一个全屏式的白色背景色布局的视图,其中仅有一个TextView控件。为了作一些改进,你可以把一个渐变形状添加到RelativeLayout上。
接下来,右击drawable文件夹并选择New->Drawable resource file。命名这个资源文件为background,并使用如下代码替换原来的内容:
- <?xml version="1.0" encoding="UTF-8"?>
- <shape xmlns:android="http://schemas.android.com/apk/res/android"
- android:shape="rectangle" >
- <gradient
- android:type="linear"
- android:startColor="#FF85FBFF"
- android:endColor="#FF008080"
- android:angle="45"/>
- </shape>
实际上,你可以根据自己的喜欢任意地修改颜色与角度。
注意:布局中的ImageButton控件使用了一个来自于https://design.google.com/icons/#ic_mic_none网站提供的图像。你可以下载并把它以资源方式添加使用。
接下来,更新文件activity_main.xml中的代码:
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/background"
- android:id="@+id/rel"
- tools:context="com.example.theodhor.speechapplication.MainActivity">
- <ImageButton
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/microphoneButton"
- android:layout_centerVertical="true"
- android:layout_centerHorizontal="true"
- android:src="@drawable/ic_mic_none_white_48dp"
- android:background="@null"/>
- </RelativeLayout>
增加说话功能
现在,用户接口部分已经完成,接下来要编写位于MainActivity内部的Java代码了。
首先,在onCreate方法上面声明一个变量TextToSpeech:
- private TextToSpeechtts;
然后,在onCreate方法中添加如下代码:
- tts = new TextToSpeech(this, new TextToSpeech.OnInitListener() {
- @Override
- public void onInit(int status) {
- if (status == TextToSpeech.SUCCESS) {
- int result = tts.setLanguage(Locale.US);
- if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
- Log.e("TTS", "This Language is not supported");
- }
- speak("Hello");
- } else {
- Log.e("TTS", "Initilization Failed!");
- }
- }
- });
上述代码将启动系统中的TextToSpeech服务。其中的speak()方法使用了一个String类型的参数,它是你要求你的Android设备需要念出的文字。
下面要创建这个方法,并添加如下代码:
- private void speak(String text){
- if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.LOLLIPOP) {
- tts.speak(text, TextToSpeech.QUEUE_FLUSH, null, null);
- }else{
- tts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
- }
- }
上面代码中使用了Build.VERSION检查,因为tts.speak(param,param,param)格式的调用对于Android API 5.1来说已经废弃了。
在speak()方法后面再创建另一个方法,用于当用户关闭程序时负责停止TextToSpeech服务:
- @Override
- public void onDestroy() {
- if (tts != null) {
- tts.stop();
- tts.shutdown();
- }
- super.onDestroy();
- }
到此,一旦你启动程序,这个程序便能说出“Hello”这样的语句了。接下来要实现的是使程序具备听的功能。
增加聆听功能
为了使程序能够具备听的功能,你需要使用麦克风按钮。为此,需要在onCreate方法中添加如下代码:
- findViewById(R.id.microphoneButton).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- listen();
- }
- });
点击ImageButton控件时,将触发调用下面这个函数:
- private void listen(){
- Intent i = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
- i.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
- i.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault());
- i.putExtra(RecognizerIntent.EXTRA_PROMPT, "Say something");
- try {
- startActivityForResult(i, 100);
- } catch (ActivityNotFoundException a) {
- Toast.makeText(MainActivity.this, "Your device doesn't support Speech Recognition", Toast.LENGTH_SHORT).show();
- }
- }
此方法将启动listening Activity,这个活动会显示一个带有一段文本提示的对话框。讲话所使用的语言是设备提供的,通过Locale.getDefault()方法实现。
StartActivityForResult (i,100)方法等待当前活动返回一个结果。100只是一个附加到已启动活动的随机代码,其实也可以是一个任何适合你需要的数字。当结果从已启动的活动返回时,它包含这个代码并使用此代码来区分来自于彼此的多个结果。
要从已启动的活动中捕获结果,需要添加下面的重写方法:
- @Override
- protected void onActivityResult(intrequestCode, intresultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- if(requestCode == 100){
- if (resultCode == RESULT_OK &&null != data) {
- ArrayList<String> res = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
- String inSpeech = res.get(0);
- recognition(inSpeech);
- }
- }
- }
这个方法捕获来自于活动的每一个结果并使用requestCode来处理语言识别器结果数据。如果requestCode等于100,requestCode等于OK并且来自于这个结果的数据不是null。你会从res.get(0)中取得result字符串。
接下来,创建一个新方法recognition,此方法将使用一个String类型的参数:
- private void recognition(String text){
- Log.e("Speech",""+text);
- }
到现在为止,当用户点击麦克风按钮时,程序能够听声音了,并且能够把用户的语言转换为文本数据,最终结果将通过Error日志打印输出。
增加学习功能
为了使程序更有趣一些,在这一小节中你要使应用程序能够学习一些简单的事情,例如你的名字。为了实现这一功能,需要使用本地存储功能。
首先,在onCreate方法中添加如下代码:
- private SharedPreferences preferences;
- private SharedPreferences.Editor editor;
- private static final String PREFS = "prefs";
- private static final String NAME = "name";
- private static final String AGE = "age";
- private static final String AS_NAME = "as_name";
然后,在onCreate方法中添加如下代码:
- preferences = getSharedPreferences(PREFS,0);
- editor = preferences.edit();
首先,你需要使应用程序提问问题,所以需要把speak("Hello")修改为speak(“What is your name?)。
在这里,您可以使用一个简单的逻辑;所以,当有人问"你的名字是什么?",答案是"我的名字是Dori",于是从答案中提出名字。一个简单的方法是把答案拆分由空格分隔的字符串并获取最后一个索引的值。
于是,我们要更新recognition方法中的代码,如下所示:
- private void recognition(String text){
- Log.e("Speech",""+text);
- //creating an array which contains the words of the answer
- String[] speech = text.split(" ");
- //the last word is our name
- String name = speech[speech.length-1];
- //we got the name, we can put it in local storage and save changes
- editor.putString(NAME,name).apply();
- //make the app tell our name
- speak("Your name is "+preferences.getString(NAME,null));
- }
recognition方法使用来自用户语音的所有结果。既然讲话可能是不同的,你可以使用它们可能包含的某些单词来区别它们。
例如,这个方法中的代码可以是:
- private void recognition(String text){
- Log.e("Speech",""+text);
- String[] speech = text.split(" ");
- //if the speech contains these words, the user is saying their name
- if(text.contains("my name is")){
- String name = speech[speech.length-1];
- Log.e("Your name", "" + name);
- editor.putString(NAME,name).apply();
- speak("Your name is "+preferences.getString(NAME,null));
- }
- }
但这仍然是一个与应用程序的简单交互。你可以让它学习你的年龄,或者给它起一个名字。
在同一个方法中,你可以尝试下面这些简单的条件:
- //This must be the age
- //Just speak: I am x years old.
- if(text.contains("years") &&text.contains("old")){
- String age = speech[speech.length-3];
- Log.e("THIS", "" + age);
- editor.putString(AGE, age).apply();
- }
- //Then ask it for your age
- if(text.contains("how old am I")){
- speak("You are "+preferences.getString(AGE,null)+" years old.");
- }
应用程序能够告诉你时间信息:
- //Ask: What time is it?
- if(text.contains("what time is it")){
- SimpleDateFormatsdfDate = new SimpleDateFormat("HH:mm");//dd/MM/yyyy
- Date now = new Date();
- String[] strDate = sdfDate.format(now).split(":");
- if(strDate[1].contains("00"))strDate[1] = "o'clock";
- speak("The time is " + sdfDate.format(now));
- }
小结
在我创建的GitHub工程(https://github.com/sitepoint-editors/SpeechApplication)中包含了更多的例子,你可以充分地进行实验并开发出你自己真正的Android助手程序。
最后,希望你喜欢这个教程,并希望你能够与自己的手机产生一次真正有用的对话。