1. <div id="f8mbs"></div>
        您好,歡迎來到源碼搜藏網!分享精神,快樂你我!
        [加入VIP] 設為首頁 | 收藏本站 | 網站地圖 | Sitemap | TAG標簽
      2. 首 頁
      3. 在線工具
      4. jquery手冊
      5. 當前位置:首頁 > 安卓源碼 > 技術博客 >

        使用Android 編寫一個簡單的大聲朗讀您的短信應用程序

        時間:2018-08-08 23:47 來源:互聯網 作者:源碼搜藏 瀏覽:收藏 挑錯 推薦 打印

        使用Android TextToSpeech API,我們可以編寫一個簡單的應用程序,大聲朗讀您的短信(短信)信息。 源代碼下載: 鏈接: https://pan.baidu.com/s/1dLLjExMHULa6Mh78DZBIXA 密碼: gi2a 我編寫了我在本文中解釋的應用程序,因為它是我自己想要的。 我經常在離 使用Android TextToSpeech API,我們可以編寫一個簡單的應用程序,大聲朗讀您的短信(短信)信息。
        源代碼下載:鏈接: https://pan.baidu.com/s/1dLLjExMHULa6Mh78DZBIXA 密碼: gi2a
        我編寫了我在本文中解釋的應用程序,因為它是我自己想要的。我經常在離開工作之前給我的妻子發短信。一般來說,我沒有注意到她的回復,因為我已經開車了,而且在開車時不看我的手機我很自律。這經常導致我錯過了她的消息,要求我在回家的路上在商店里挑選一些東西。

        現在我只需啟動我的Android應用程序,我的手機就會使用  TextToSpeech API在我開車時向她讀取她(或任何傳入的短信)消息。  

        更新 - 修復所有版本的權限運行(KitKat通過Nugat)

        我修復了Marshmallow和Nugat上SMS Text的權限問題,現在這段代碼將在所有版本上運行。獲取上面的v2并在支持TextToSpeech的任何版本上運行。有關添加的代碼的詳細信息,請參閱下面的修復權限部分

        警告-請注意 MarshmallowNugat 用戶-在這一點上我很興奮,所以我用的版本,釋放它釋放本文將在Android 4.3的工作-棒棒堂(5.1.1) 在Lollipop之后,Android為SMS提供了更多安全性,因此我必須添加代碼以獲取SMS消息,該消息在第一次運行時警告用戶。該代碼暫時不適用于這些平臺。我會盡快更新。現在,我希望你會閱讀,也許到你完成時我會把它修好(下一天或兩天 - 目標為2017年4月27日)。 

        第一版很難看(基本用戶界面)

        第一個版本并不漂亮,因為我只是想要功能,并且對創建漂亮的UI不感興趣。這是一個基本的空Android表單(Activity),我添加了一些基本控件。下圖顯示了EditText和一個按鈕,您可以使用該按鈕鍵入所需的任何文本,并讓應用程序為您說出文本。  

        我稱應用程序Vext(語音文本portmanteau ^)。

        使用Android 編寫一個簡單的大聲朗讀您的短信應用程序

        在派對上的樂趣

        您可以在EditText控件中鍵入所需的任何文本,按[Speak]按鈕,應用程序將以默認設備語音為您說出。你將成為你參加的每一個派對的熱門話題。:)

        觀看該應用在這個非常短的視頻中講一個簡短的短語。

        https://youtu.be/D5X3z7miXjQ  (在新標簽頁中打開)

        在活動的更下方的SeekBar控件(在Windows世界中也稱為Slider)允許您設置語音的音量。應用程序首次啟動時,通過在MainActivity上調用以下方法獲取最大卷:

        int maxVol = am.getStreamMaxVolume(am.STREAM_MUSIC);

        第一次運行時,它將默認為3.設置值后,我將值存儲在SharedPreferences中,以便應用程序的每次初始運行都會記住您希望語音的音量。

        我們將在本文的正文中詳細介紹這些細節。這是我們將在本文中介紹的概念。

        我們將涵蓋的概念

        • 接收短信,抓取信息正文
        • 使用TextToSpeech API
        • 在SharedPreferences中設置和保存TextToSpeech卷

        調用功能

        目前,運行該應用程序將是打開和關閉該功能的方法。這意味著,啟動應用程序,將向您讀取以下傳入消息。停止應用程序,您的文本將不再被大聲朗讀。

        Android Widget

        這個應用程序很適合作為Android Widget(可從您的家和鎖屏獲得),我已經在努力了。但是,用于小部件的Android API很脆弱且難以使用。事情肯定會更容易。正如我試圖實現它,我遇到了無法解釋的錯誤。直到我得到那些修復,我們將不得不滿足于這個基本的應用程序。

        這是一個很長的介紹所以讓我們跳進一些代碼。我們首先來看看一切開始的MainActivity代碼。

        MainActivity onCreate()

        當Android應用程序啟動時,將加載MainActivity并onCreate()調用函數。該方法使我們有機會在應用程序啟動時進行一些初始化。我不會向您展示UI組件的所有初始化,因此我可以專注于本文的主題。我們在onCreate()中看到的第一個對我們感興趣的代碼是:

        AudioManager am = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
        int maxVol = am.getStreamMaxVolume(am.STREAM_MUSIC);
        Log.d("MainActivity", "max vol : " + String.valueOf(maxVol));
        volumeSeekBar.setMax(maxVol);

        設置UI組件(SeekBar)

        此代碼允許我們使用。獲取系統音頻服務的最大音量級別AudioManager要設置TextToSpeech語音的音量,我們將使用setStreamVolume()稍后命名的AudioManager方法這部分代碼獲得了可能的最大音量,因此我們可以設置我們的SeekBar(思考滑塊)最大值。通常這個值大約是13到15.這確保了用戶只能使用SeekBar將音量設置為有效值。

        設置當前音量

        下一行調用我編寫的設置當前音量值的方法:

        setCurrentVolumeLevel();

        該方法在MainActivity.java文件中稍微向下,它看起來像:

        private void setCurrentVolumeLevel() {
         SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
         int volumeLevel = 0;
         volumeLevel = preferences.getInt("volumeLevel", 3);
         volumeSeekBar.setProgress(volumeLevel);
        }

        使用SharedPreferences非常簡單且有幫助

        此方法向您展示如何從Android讀取SharedPreferences這些值只能由此應用程序讀取和寫入,因此它們被認為是安全的。當然,我們只是保存并檢索當前卷的值,因此無關緊要。使用SharedPreferences的價值在于,每次運行應用程序時都會設置和記住我們的值。

        一旦我們獲得了我們從中獲取的preferences 對象,我們就PreferenceManager可以查詢它可能已經保存的值。在我們的例子中,我們正在尋找一個名為的整數值volumeLevel我們使用的getInt()方法是獲取我們要查找的值的名稱,如果找不到則返回默認值(在我們的例子中為3)。應用程序第一次運行時,將找不到該值,因此我們將該值設置為3。

        更新SeekBar UI

        獲得值(或默認值)后,我們只需setProgress()使用值調用方法,以確保使用正確的值更新SeekBar UI。該方法返回,我們又回來了onCreate()

        意圖和廣播

        在Android世界中,只要您想要解決一些通用功能,您就可以使用Intent來實現。例如,如果您希望用戶能夠通過您的應用觀看視頻,則可能已有可用的視頻服務。這意味著您只需要正確設置一個Intent并請求服務處理該操作。  

        對于Vext,我認為使TextToSpeech 功能可用的最簡單方法是創建一個BroadcastReceiver,我們可以在需要時通過Intent調用它。這也將允許在我實現Android Widget時更容易訪問該功能(稍后將詳細介紹)。

        正如我所說,你可以在你的應用程序之外請求功能,但在我們的情況下,我想保持服務本地,我已經知道我可以通過創建一個下降的類來做到這一點BroadcastReceiver稍后,我們將看到這個添加的類名為  TTSReceiver

        在MainActivity onCreate()中,您可以看到我在何處初始化lbm 為此用途命名的成員變量,然后創建一個新變量TTSReceiver

        lbm = LocalBroadcastManager.getInstance(this);
        ttsReceiver = new TTSReceiver();

        這將準備TextToSpeech系統,因為我們將使用它。但是要了解如何在我們的應用程序中實現TextToSpeech,讓我們仔細看看TTSReceiver類。

        public class TTSReceiver extends BroadcastReceiver {
            private TextToSpeech tts;
            private Set<Voice> allVoices;
            private String messageBodyText;
            private TextToSpeech.OnInitListener ttsListener;
        
            @Override
            public void onReceive(Context context, Intent intent) {
        
                Log.d("MainActivity", "onReceive() fired!");
                SharedPreferences preferences = 
                      PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
                int volumeLevel = 0;
                volumeLevel = preferences.getInt("volumeLevel",3);
                Log.d("MainActivity", "volumeLevel : " + String.valueOf(volumeLevel));
                AudioManager am = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
                am.setStreamVolume(am.STREAM_MUSIC, volumeLevel, 0);
        
                messageBodyText =  intent.getStringExtra("MESSAGE_BODY");
        
                if (ttsListener == null) {
                    ttsListener = new TextToSpeech.OnInitListener() {
                        @Override
                        public void onInit(int status) {
                            // tts.speak(messageBodyText, TextToSpeech.QUEUE_ADD, null, "1st1");
                        }
                    };
                }
        
                if (tts == null) {
                    tts = new TextToSpeech(context, ttsListener);
                }
        
                tts.speak(messageBodyText, TextToSpeech.QUEUE_ADD, null, "2nd1");
            }
        }

        這個類非常簡單,我們將回到MainActivity代碼,稍后通過Intent調用它,這樣你就可以看到它是如何被調用的。但是,首先讓我們來看看我們在這里有什么。

        BroadcastReceiver onRecieve()

        BroadcastReceiver 調用它時,很容易采取一些操作您只需覆蓋該onReceive()方法,操作系統會在事件發生時通知您。這是當你新建Intent并通過它調用BroadcastReceiver時將運行的代碼LocalBroadcastManager您可以查看這些基礎知識的更多詳細信息,但是讓我添加此類必須注冊的位置,以便您了解系統如何知道如何查找此類。

        AndroidManifest.xml中

        每當您添加BroadcastReceiver時,您還必須向系統注冊該類,以便它知道如何查找該類。您可以通過AndroidManifest 項目中找到來實現。雖然我不喜歡在讀者身上放一堆代碼,但我會在這里展示整個AndroidManifest,因為我們還需要允許一些Android權限,你現在也可以看到它們。我還將粗體顯示TTSReceiver定義的部分,以便您可以看到它。  

        大多數是在AndroidManifest 創建項目時由Android Studio項目模板生成的。

        <?xml version="1.0" encoding="utf-8"?>
        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        
            package="us.raddev.vext">
            <uses-permission android:name="android.permission.RECEIVE_SMS" />
            <uses-permission android:name="android.permission.READ_CONTACTS"/>
            <application
        
                android:allowBackup="true"
        
                android:icon="@mipmap/ic_launcher"
        
                android:label="@string/app_name"
        
                android:supportsRtl="true"
        
                android:theme="@style/AppTheme">
                <activity android:name=".MainActivity">
                    <intent-filter>
                        <action android:name="android.intent.action.MAIN" />
        
                        <category android:name="android.intent.category.LAUNCHER" />
                    </intent-filter>
                </activity>
                <receiver android:name=".MsgReceiver">
                    <intent-filter>
                        <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
                    </intent-filter>
                </receiver>
                <receiver android:name=".TTSReceiver">
                    <intent-filter>
                        <action android:name="us.raddev.vext.message" />
                    </intent-filter>
                </receiver>
            </application>
        </manifest>

        Android權限

        收到短信

        如您所見,前兩個粗體線是我添加的權限。第一個允許我們的應用程序接收短信。這意味著用戶將在安裝應用程序時收到警告。如果用戶想要她可以取消安裝。  

        閱讀聯系信息

        此應用還需要閱讀聯系信息以獲取向您發送消息的用戶的名稱。  

        仔細觀察,您會發現我們的MainActivity也在清單(.MainActivity)中注冊。

        TTSReceiver注冊一個動作

        您還可以看到TTSReceiver注冊了一個名為“us.raddev.text.message”的動作。這是我們將添加到Intent的動作,這樣當我們廣播動作時就會觸發。

        當動作觸發時,該onReceive() 方法將運行,我們可以運行我們的代碼。

        當onReceive()方法事件發生時,我們執行以下操作:

        從首選項中讀取音量級別

        SharedPreferences preferences =
          PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext()); int volumeLevel = 0;
         volumeLevel = preferences.getInt("volumeLevel",3);

        我們將音量級別存儲在變量中,以便我們可以使用它來設置TextToSpeech 引擎將使用的音量級別

        設置AudioManager音量級別

        AudioManager am = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); 
        am.setStreamVolume(am.STREAM_MUSIC, volumeLevel, 0);

        讀取字符串傳遞:MESSAGE_BODY

        messageBodyText =  intent.getStringExtra("MESSAGE_BODY");

        當我們創建我們的Intent(回到MainActivity onCreate() - 稍后將顯示此代碼)時,我們在Intent上設置一個字符串,我們將使用名稱“MESSAGE_BODY”來引用它。在這里,我們獲取該文本并將其保存到名為messageBodyText的成員變量中。  

        這是什么文字?

        這通常是文本消息的主體。但是,由于我們使用此BroadcastReceiver來對TextToSpeech進行任何調用,因此這是我們想要大聲說出的任何文本。

        最后,我們準備初始化TextToSpeech,以便它為我們說出我們的文本。

        初始化TextToSpeech

        if (ttsListener == null) {
            ttsListener = new TextToSpeech.OnInitListener() {
                @Override
                public void onInit(int status) {
                    // tts.speak(messageBodyText, TextToSpeech.QUEUE_ADD, null, "1st1");
                }
            };
        }
        
        if (tts == null) {
            tts = new TextToSpeech(context, ttsListener);
        }

        您可以看到我們必須初始化,TTSListener 以便我們可以使用它來初始化TextToSpeech 它實際上會說文本對象。我將這些對象存儲在成員變量中,以便在應用程序的生命周期內初始化TTS。但是,我確實遇到了一些陌生感。

        奇怪的事情,重復或不說話

        嘗試初始化TextToSpeech時遇到了一些問題。我發現如果我在上面顯示的onInit()方法中進行了第一次調用(現在已經注釋,因為它不應該使用),TextToSpeech會重復短語。這很奇怪,代表了一個挑戰,因為當我沒有這樣做時,TextToSpeech就不會說我的任何文字了。  

        解決方法和它的工作原理

        我最后通過第一次調用初始化TTS來解決這個問題,該調用要求它說一個空字符串。是的,這似乎很荒謬,但我了解到其他人也有奇怪的重復。閱讀此StackOverflow以獲取更多信息: 

        連續調用TextToSpeech.OnInitListener.onInit(int)^

        一旦所有內容都被初始化,我們就可以調用speak()方法并讓它說出我們的文本。

        TextToSpeech Speak()方法

        tts.speak(messageBodyText, TextToSpeech.QUEUE_ADD, null, "2nd1");

        一旦掌握了所有這些,就可以輕松完成。當然,你必須設置BroadcastReceiver,否則這將無法正常工作。speak()方法需要三個參數,我們應該更仔細地了解它們:

        1. messageBodyText:TTS將發言的文本
        2. TextToSpeech.QUEUE_ADD:如何處理多個發言請求 - 在我們的例子中,我們告訴它將每個請求添加到隊列并在可能的情況下說出來。你也可以使用QUEUE_FLUSH,它會刷新(取消)其他人,只說最新的。
        3. 字符串:在我們的例子中,我添加了“2nd1”,這是毫無意義的。這只是一個用于標識消息的字符串。

        現在我們已經看到了TTSReceiver(BroadcastReceiver)如何工作,現在我們可以更好地了解如何調用它。我們用方法用空字符串(如前所述)進行第一次調用MainActivity.onCreate()

        以下是我們如何創建Intent并調用TTSReceiver來說出一些文本:

        Intent intent = new Intent("us.raddev.vext.message");
        intent.putExtra(MESSAGE_BODY,"" );
        lbm.sendBroadcast(intent);

        當我們創建Intent時,我們提供了我們想要采取的動作的名稱。請記住,“.message”是任意選擇的。它可能是“us.raddev.vext.elephant”如果我想要的話。:)

        接下來,我們將Extra(字符串)添加到Intent并將其命名為“MESSAGE_BODY”。在這種情況下,我們添加的字符串是一個空字符串,所以它不是那么令人興奮。  

        廣播我們的意圖

        最后我們調用我們LocalBroadcastManager 的方法并使用我們的方法調用sendBroadcast方法intent當我們這樣做時,系統找到匹配的類(TTSReceiver)并onReceive()運行方法。就這么簡單。

        您可以看到非常相似的代碼附加到說話按鈕onclick監聽器。這樣,當用戶鍵入一些文本并單擊MainActivity上的按鈕時,她將聽到它說出來。

        speakButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                String outText = textToSpeak.getText().toString();
                if (outText != null) {
                    Intent intent = new Intent("us.raddev.vext.message");
                    intent.putExtra(MESSAGE_BODY,outText );
                    lbm.sendBroadcast(intent);
                    Log.d("MainActivity", "Button click ended!");
                }
            }
        });

        我已經加粗了上面的重要代碼。您可以看到,這里的最大區別是我們從textToSpeak EditText控件獲取文本,并且當我們在Intent上調用putExtra時使用它。

        這是我們在TTSReceiver.onReceive()方法中檢索的字符串,因此該TextToSpeech.speak()方法知道該說什么。

        一切如何工作現在更有意義

        現在我們已經了解了所有這些,了解SMS文本消息到達時我們將會做什么將會容易得多。現在唯一的區別是我們的應用程序將說出SMS文本消息中的單詞。它是如何做到的?一樣的方法。唯一的另一件事是我們獲取SMS的正文文本并將其傳遞給我們的TTSReceiver,以便它為我們說話。

        請更多BroadcastReceiver

        在Android上接收短信并獲取正文非常容易。現在你更容易理解a,BroadcastReceiver 因為接收SMS也是通過BroadcastReceiver完成的。你甚至可以谷歌如何做到這一點。回顧上面的AndroidManifest并查找文本.MsgReceiver,您將看到我們在MsgReceiver 收到傳入短信時注冊了一個名為運行的類

        這是我們MsgReceiver 班級的樣子。同樣,一切都在onReceive()方法中發生

        public void onReceive(Context context, Intent intent) {
            if (lbm == null && ttsReceiver == null) {
                lbm = LocalBroadcastManager.getInstance(context);
                ttsReceiver = new TTSReceiver();
                lbm.registerReceiver(ttsReceiver,new IntentFilter("us.raddev.vext.message"));
            }
        
            SmsMessage message = null;
            String from = null;
        
            message = GetMessage(intent);
            from = message.getOriginatingAddress();
        
            if (message == null){
                message = GetMessage(intent);
            }
        
            from = message.getOriginatingAddress();
            String body = message.getMessageBody();
            Toast.makeText(context,body,  Toast.LENGTH_SHORT).show();
            long receivedDate = message.getTimestampMillis();
            Date date = new Date(receivedDate);
            DateFormat formatter = new SimpleDateFormat("MM/dd/yyyy - HH:mm:ss");
            String formattedDate = formatter.format(date);
        
            ///Resolving the contact name from the contacts.
            Uri lookupUri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, 
                   Uri.encode(from));
            Cursor c = context.getContentResolver().query(lookupUri, new String[]
                    {ContactsContract.Data.DISPLAY_NAME},null,null,null);
            try {
                Intent ttsIntent = new Intent("us.raddev.vext.message");
                boolean isSuccess = c.moveToFirst();
                if (isSuccess) {
                    // got a contact name
                    String displayName = c.getString(0);
                    String ContactName = displayName;
                    Log.d("MainActivity", "ContactName : " + ContactName);
                    ttsIntent.putExtra(MESSAGE_BODY,"Incoming from " + ContactName );
                }
                else{
                    //doesn't have name in contacts
                    ttsIntent.putExtra(MESSAGE_BODY,"Incoming message");
                }
                lbm.sendBroadcast(ttsIntent);
                lbm.unregisterReceiver(ttsReceiver);
            }
            catch (Exception e) {
                // TODO: handle exception
            }finally{
                c.close();
            }
        
            Intent ttsIntent = new Intent("us.raddev.vext.message");
            ttsIntent.putExtra(MESSAGE_BODY,body );
            lbm.sendBroadcast(ttsIntent);
            lbm.unregisterReceiver(ttsReceiver);
        
            Log.d("MainActivity", "from : " + from);
            Log.d("MainActivity", "body : " + body);
            Log.d("MainActivity", "receivedDate : " + formattedDate);
        
        }

        您可以簡單地閱讀該代碼和幾條評論,并找出所做的一切。

        但是,讓我總結一下它的作用。

        SMS MsgReceiver摘要

        1. 檢查成員變量以查看它們是否已經初始化(或者這是否是首次運行)。
        2. 調用名為的本地方法GetMessage()獲取實際的SMS消息對象。這種方法簡單地包含了一些東西,因為Android SMS已經更改了版本。  
        3. 從SMS消息對象中獲取我們想要使用的一些信息(originatingAddresstextBody
        4. 通過originatingAddress from獲取聯系- 如果存在
        5. 如果存在聯系請求TTSReceiver宣布“從<contactname>傳入”
        6. 如果聯系人不存在,請求TTSReceiver宣布“傳入消息”
        7. 要求TTSReceiver 發言文本正文。

        而已。

        這很容易。抓取代碼并在Android手機上試用。我想你真的很喜歡它。

        修復權限

        以前我遇到過一個問題,我沒有在Marshmallow(6.x)及更高版本上正確地請求權限。我已經研究過如何做到這一點,而且添加的代碼不多。    

        App首次運行

        您將此代碼添加到您MainActivity 的應用程序中,以便當用戶第一次通知應用程序正在請求權限并且必須響應以允許權限時運行應用程序。同樣,只有當應用程序在Marshmallow或更新版本上運行時才會出現這種情況如果權限在Lollipop或更低版本,則以常規方式處理權限。

        這是用戶的樣子。在我們的例子中,我們需要兩個權限(RECEIVE_SMS和READ_CONTACTS),因此用戶被查詢兩次,每次訪問一次。

        使用Android 編寫一個簡單的大聲朗讀您的短信應用程序使用Android 編寫一個簡單的大聲朗讀您的短信應用程序

        拒絕任何一個和Vext將無法工作

        如果用戶拒絕,那么Vext應用程序將無法運行。這可以通過將聯系人的讀取移出MsgReceiver類來解決,但我現在不會擔心這一點。現在,這是全有或全無。如果用戶在不允許權限的情況下運行應用程序并且SMS文本到達,則應用程序將崩潰。沒有警告沒有設置燙發。在開發Android應用程序時,這可能會有點混亂,因此請記住這一點。

        這是我添加到MainActivity以處理權限的代碼。  

        許可方法

        我添加了一個我命名的新方法,requestAllPermissions()并在MainActivity.onCreate()方法的頂部添加了一個調用,以確保在第一次運行應用程序時查詢用戶。

        這是非常直接的整個方法:

        private void requestAllPermissions() {
            String permission = Manifest.permission.RECEIVE_SMS;
            String permission2 = Manifest.permission.READ_CONTACTS;
            int grant = ContextCompat.checkSelfPermission(this, permission);
            if ( grant != PackageManager.PERMISSION_GRANTED) {
                String[] permission_list = new String[2];
                permission_list[0] = permission;
                permission_list[1] = permission2;
                ActivityCompat.requestPermissions(this, permission_list, 2);
            }
        }

        您所做的就是設置一個字符串權限數組,然后將它們添加到ActivityCompat.requestPermissions()方法并調用該方法。一旦該代碼運行并且用戶接受該代碼,該應用程序就會為這些權限設置。

        就這么簡單。

        使用Android 編寫一個簡單的大聲朗讀您的短信應用程序轉載http://www.rhcg.tw/appboke/38812.html
        標簽:網站源碼
        辽宁十一选五单双