推薦閱讀:
SurfaceView+MediaPlayer封裝之路
Android學習資源分享合集(1)java
最近寫了一個金額的語音播報功能,已封裝成依賴庫到Github,但願對你們有所幫助。
Github地址 :
https://github.com/javaexcept...git
思路:
(1).準備音頻文件。
(2).把要播報的金額轉換成大寫的金額,好比"零壹貳叄肆伍陸柒捌玖,分角 拾佰仟萬拾佰仟億拾佰仟萬"的組合。
(3).經過MediaPlayer播放音頻。github
下面是我音頻文件,裏面是大寫的數字,爲播報金額組合作準備。api
public class PlaySound { /** * 截取字符串 * * @param str 須要截取的字符串 * @param idx1 開始位置 * @param idx2 截止位置 * @return 截取後的字符串 */ public static String subString(String str, int idx1, int idx2) { try { return str.substring(idx1, idx2); } catch (Exception ex) { return ""; } } /** * 傳遞一個字符串參數,若是是null返回「」字符串,不然去除先後的空格。 * * @param str 傳入參數 * @return 沒有先後沒有空格的字符串 */ public static final String trim(String str) { if (str == null) return ""; else return str.trim(); } /** * 把double類型數據轉換成有格式的字符串 * * @param d 須要轉換的double類型數據 * @param format 格式化方式 * @return 有格式的字符串 */ public static String formatDoubleToString(double d, String format) { String doubleStr = String.valueOf(d); java.text.DecimalFormat decf = new java.text.DecimalFormat(format); String formatStr = decf.format(d); /** * 經過java保留小數了 * 若是轉換前的長度>轉換後的長度,Java的轉換就有可能出錯 */ if (doubleStr.length() > formatStr.length()) { /** * 若是前面的都一致,但最後一位大於4就須要進位 * 不然不進位 */ if (formatStr.equals(doubleStr.substring(0, formatStr.length()))) { /** * 取轉換前的後一位, * 有多是「.」 */ String followStr = doubleStr.substring(formatStr.length(), formatStr.length() + 1); if (".".equals(followStr)) { followStr = doubleStr.substring(formatStr.length() + 1, formatStr.length() + 2); } if (Integer.valueOf(followStr).intValue() > 4) { /** * 這個時候Java沒有進位 */ formatStr = decf.format(Double.valueOf(formatStr).doubleValue() + Double.valueOf(format.substring(0, format.length() - 1) + "1"). doubleValue()); } } } return formatStr; } /** * 把一個都money轉換成大寫的money * * @param d 須要轉換的money * @return 換成大寫的money */ public static String capitalValueOf(double d) { String lowStr; int strLen; String currentStr; String upperPart; String upperStr = ""; int index = 0; int findCount; String chns = "零壹貳叄肆伍陸柒捌玖"; String units = "分角 拾佰仟萬拾佰仟億拾佰仟萬"; if (d >= 100000000 || d < 0) { return ""; } if (d == 0) { return "零元整"; } lowStr = trim(formatDoubleToString(d, "0.00")); strLen = lowStr.length(); if (strLen == 0) { return ""; } while (index < strLen) { currentStr = subString(lowStr, strLen - index - 1, strLen - index); if (".".equals(currentStr)) { upperPart = "元"; } else { upperPart = subString(chns, Integer.valueOf(currentStr).intValue(), Integer.valueOf(currentStr).intValue() + 1); } upperPart += trim(subString(units, index, index + 1)); upperStr = upperPart + upperStr; index += 1; } for (; ; ) { findCount = 0; if (upperStr.indexOf("拾零萬零仟") < 0) { if (upperStr.indexOf("拾零萬") >= 0) { if ("仟".equals(subString(upperStr, upperStr.indexOf("拾零萬") + 4, upperStr.indexOf("拾零萬") + 5))) { findCount++; upperStr = upperStr.replaceFirst("拾零萬", "拾萬零"); } } } if (upperStr.indexOf("零元") >= 0) { findCount++; upperStr = upperStr.replaceAll("零元", "元"); } if (upperStr.indexOf("零拾") >= 0) { findCount++; upperStr = upperStr.replaceAll("零拾", "零"); } if (upperStr.indexOf("零佰") >= 0) { findCount++; upperStr = upperStr.replaceAll("零佰", "零"); } if (upperStr.indexOf("零仟") >= 0) { findCount++; upperStr = upperStr.replaceAll("零仟", "零"); } if (upperStr.indexOf("零萬") >= 0) { findCount++; upperStr = upperStr.replaceAll("零萬", "萬"); } if (upperStr.indexOf("零億") >= 0) { findCount++; upperStr = upperStr.replaceAll("零億", "億"); } if (upperStr.indexOf("零零") >= 0) { findCount++; upperStr = upperStr.replaceAll("零零", "零"); } if (upperStr.indexOf("零角零分") >= 0) { findCount++; upperStr = upperStr.replaceAll("零角零分", "整"); } if (upperStr.indexOf("零分") >= 0) { findCount++; upperStr = upperStr.replaceAll("零分", "整"); } if (upperStr.indexOf("零角") >= 0) { findCount++; upperStr = upperStr.replaceAll("零角", "零"); } if (upperStr.indexOf("零億零萬零元") >= 0) { findCount++; upperStr = upperStr.replaceAll("零億零萬零元", "億元"); } if (upperStr.indexOf("億零萬零元") >= 0) { findCount++; upperStr = upperStr.replaceAll("億零萬零元", "億元"); } if (upperStr.indexOf("零億零萬") >= 0) { findCount++; upperStr = upperStr.replaceAll("零億零萬", "億"); } if (upperStr.indexOf("零萬零元") >= 0) { findCount++; upperStr = upperStr.replaceAll("零萬零元", "萬元"); } if (upperStr.indexOf("萬零元") >= 0) { findCount++; upperStr = upperStr.replaceAll("萬零元", "萬元"); } if (findCount == 0) { break; } } while ("元".equals(subString(upperStr, 0, 1)) || "零".equals(subString(upperStr, 0, 1)) || "角".equals(subString(upperStr, 0, 1)) || "分".equals(subString(upperStr, 0, 1)) || "整".equals(subString(upperStr, 0, 1))) { strLen = upperStr.length(); upperStr = subString(upperStr, 1, strLen); } return upperStr; } public static void main(String[] args){ } }
1.MediaPlayer簡介微信
MediaPlayer實際上是一個封裝的很好的音頻、視頻流媒體操做類,若是查看其源碼,會發現其內部是調用的native方法,既然是一個流媒體操做類,那麼必然涉及到,播放、暫停、中止等操做,實際上MediaPlayer也爲咱們提供了相應的方法來直接操做流媒體。
void start():開始或恢復播放。app
void stop():中止播放。異步
void pause():暫停播放。 maven
經過上面三個方法,只要設定好流媒體數據源,便可在應用中播放流媒體資源,爲了更好的操做流媒體,MediaPlayer還爲咱們提供了一些其餘的方法,這裏列出一些經常使用的,詳細內容參閱官方文檔。
int getDuration():獲取流媒體的總播放時長,單位是毫秒。ide
int getCurrentPosition():獲取當前流媒體的播放的位置,單位是毫秒。oop
void seekTo(int msec):設置當前MediaPlayer的播放位置,單位是毫秒。
void setLooping(boolean looping):設置是否循環播放。
boolean isLooping():判斷是否循環播放。
boolean isPlaying():判斷是否正在播放。
void prepare():同步的方式裝載流媒體文件。
void prepareAsync():異步的方式裝載流媒體文件。
void release ():回收流媒體資源。
void setAudioStreamType(int streamtype):設置播放流媒體類型。
void setWakeMode(Context context, int mode):設置CPU喚醒的狀態。
setNextMediaPlayer(MediaPlayer next):設置當前流媒體播放完畢,下一個播放的MediaPlayer。
在使用start()播放流媒體以前,須要裝載流媒體資源。
2.MediaPlayer實現播報源碼
public class VoiceUtils { private static volatile VoiceUtils singleton = null; public boolean IsPlaying; MediaPlayer mediaPlayer=null; private Context mContext; public VoiceUtils(Context context) { this.mContext = context.getApplicationContext(); } /** * 單例 * @param context * @return */ public static VoiceUtils with(Context context){ if (singleton == null) { synchronized (VoiceUtils.class) { if (singleton == null) { singleton = new VoiceUtils(context); } } } return singleton; } public void SetIsPlay( boolean IsPlaying){ this.IsPlaying=IsPlaying; } public boolean GetIsPlay() { return IsPlaying; } public void Play(String stramount,boolean strsuccess) { String str=null; //若是是TRUE 就播放「收款成功」這句話 if (strsuccess){ str = "$" + PlaySound.capitalValueOf(Double.valueOf(String.format("%.2f", Double.parseDouble(stramount)))); }else { str = PlaySound.capitalValueOf(Double.valueOf(String.format("%.2f", Double.parseDouble(stramount)))); } System.out.println("金額的長度 "+str); String temp =""; try { Thread.sleep(1000); } catch (InterruptedException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } PlaySoundList(1,str,str.length()); } public void PlaySoundList( final int soundindex, final String soundString, final int soundcount) { singleton.SetIsPlay(true); boolean createState=false; if(mediaPlayer==null) { mediaPlayer = null; } System.out.println("加載音頻["+soundindex+"]"); mediaPlayer = createSound(soundindex,soundString); createState=true; if(createState==true) System.out.println("加載音頻成功["+soundindex+"]"); else System.out.println("加載音頻失敗["+soundindex+"]"); //播放完成觸發此事件 mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { mp.release();//釋放音頻資源 int newsoundindex =soundindex; System.out.println("釋放資源[" +soundindex+"]"); if(soundindex<soundcount) { newsoundindex=newsoundindex+1; PlaySoundList(newsoundindex, soundString,soundcount); }else { singleton.SetIsPlay(false); } } }); try { //在播放音頻資源以前,必須調用Prepare方法完成些準備工做 if(createState) mediaPlayer.prepare(); else mediaPlayer.prepare(); //開始播放音頻 mediaPlayer.start(); System.out.println("播放音頻["+soundindex+"]"); } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public MediaPlayer createSound(int soundIndex, String soundString){ MediaPlayer mp=null; String soundChar = soundString.substring(soundIndex-1,soundIndex); switch (soundChar) { case "零": mp=MediaPlayer.create(mContext,R.raw.sound0); break; case "壹": mp=MediaPlayer.create(mContext,R.raw.sound1); break; case "貳": mp=MediaPlayer.create(mContext,R.raw.sound2); break; case "叄": mp=MediaPlayer.create(mContext,R.raw.sound3); break; case "肆": mp=MediaPlayer.create(mContext,R.raw.sound4); break; case "伍": mp=MediaPlayer.create(mContext,R.raw.sound5); break; case "陸": mp=MediaPlayer.create(mContext,R.raw.sound6); break; case "柒": mp=MediaPlayer.create(mContext,R.raw.sound7); break; case "捌": mp=MediaPlayer.create(mContext,R.raw.sound8); break; case "玖": mp=MediaPlayer.create(mContext,R.raw.sound9); break; case "拾": mp=MediaPlayer.create(mContext,R.raw.soundshi); break; case "佰": mp=MediaPlayer.create(mContext,R.raw.soundbai); break; case "仟": mp=MediaPlayer.create(mContext,R.raw.soundqian); break; case "角": mp=MediaPlayer.create(mContext,R.raw.soundjiao); break; case "分": mp=MediaPlayer.create(mContext,R.raw.soundfen); break; case "元": mp=MediaPlayer.create(mContext,R.raw.soundyuan); break; case "整": mp=MediaPlayer.create(mContext,R.raw.soundzheng); break; case "萬": mp=MediaPlayer.create(mContext,R.raw.soundwan); break; case "$": mp=MediaPlayer.create(mContext,R.raw.soundsuccess); break; } //下面這三句是控制語速,可是隻適用於Android6.0 以上,如下的就會報錯,因此這個功能下次更新時解決 // PlaybackParams pbp = new PlaybackParams(); // pbp.setSpeed(1.5F); // mp.setPlaybackParams(pbp); mp.stop(); return mp; } }
Gradle依賴 -
1.最app外層的build.gradle 添加代碼:
allprojects { repositories { jcenter() maven { url 'https://jitpack.io' } } }
2.在app 的build.gradle中添加:
dependencies { compile 'com.github.javaexception:VoiceAnnouncements:v1.2' }
使用方法 -
1.普通調用:我想強調的是傳入的金額最多精確到」分」,還有在調用的時候應該進行try-catch由於若是傳入的不是金額,會出現異常的。 若是是true播報語音爲」收款成功+收款金額」,若是是false只播報收款金額。
//普通用法 VoiceUtils.with(this).Play("111",true);
2.防止用戶同時接收多條語音形成語音重疊的調用方法:
private synchronized void Play(final String str) { if (VoiceUtils.with(this).GetIsPlay()){ System.out.println("正在播放語音 "); new Thread() { @Override public void run() { super.run(); try { Thread.sleep(100);//休眠0.1秒 Play(str); } catch (InterruptedException e) { e.printStackTrace(); } /** * 要執行的操做 */ } }.start(); }else { System.out.println("不衝突"); VoiceUtils.with(this).Play(str,true); } }
播報語速的調控問題,如今由於只能支持Android6.0以上的,因此代碼我沒添加,等解決後一塊兒更新。
若是有什麼不清楚的能夠加我公衆號或者加微信,但願對你們有所幫助。