記錄小米 4,錘子手機上播放系統鈴聲失敗的問題
阿新 • • 發佈:2019-01-23
最近遇到一個問題,發現部分機型如:小米 4,錘子 Pro2 呼叫如下程式碼播放系統鈴聲失敗:
try {
Uri defaultRingtoneUri = RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE);
mediaPlayer.setDataSource(context, defaultRingtoneUri);
mediaPlayer.prepare();
mediaPlayer.start();
} catch (IOException e) {
e.printStackTrace ();
}
日誌中捕獲瞭如下異常資訊:
System.err: java.io.IOException: setDataSource failed.
W/System.err: at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1101)
W/System.err: at android.media.MediaPlayer.setDataSource(MediaPlayer.java:1047)
W/System.err: at android.media.MediaPlayer.setDataSource (MediaPlayer.java:992)
W/System.err: at android.media.MediaPlayer.setDataSource(MediaPlayer.java:971)
W/System.err: at com.example.rongcloud.myapplication.ActivityA.onCreate(ActivityA.java:30)
W/System.err: at android.app.Activity.performCreate(Activity.java:6801)
W/System.err: at android.app .Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
W/System.err: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2686)
W/System.err: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2794)
W/System.err: at android.app.ActivityThread.-wrap12(ActivityThread.java)
W/System.err: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1541)
W/System.err: at android.os.Handler.dispatchMessage(Handler.java:102)
W/System.err: at android.os.Looper.loop(Looper.java:163)
W/System.err: at android.app.ActivityThread.main(ActivityThread.java:6358)
W/System.err: at java.lang.reflect.Method.invoke(Native Method)
W/System.err: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:901)
W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:791)
發現這個問題後首先就是去打斷點看下獲取到的 Uri 是否有問題:
- 小米 4 上獲取到的 uri 為:file:///system/media/audio/ringtones/MI.ogg
- 錘子 pro2 上獲取到的 uri 為:null
錘子手機獲取到的 uri 為 null,呼叫 setDataSource 失敗可以理解,然而小米手機獲取到的 uri 不為 null 為什麼呼叫 setDataSource 還會失敗?
為一探究竟,想到可以使用 adb shell 檢視手機中是否存在這個檔案:
admindeMacBook-Pro-2:~ admindeMacBook$ adb shell
meri:/ $ cd system/media/audio/ringtones/
meri:/system/media/audio/ringtones $ ls
AcousticGuitar.ogg Country.ogg Lollipop.ogg NewDay.ogg
Bells.ogg Echo.ogg MIX.ogg Orange.ogg
Blues.ogg Enthusiastic.ogg Mi.ogg Raindrops.ogg
Breeze.ogg Fantasy.ogg MiGlass.ogg Sunrise.ogg
Carousel.ogg Future.ogg MiRemix.ogg Thinker.ogg
Celesta.ogg Glockenspiel.ogg MiXylophone.ogg ToyRobot.ogg
Childhood.ogg Leisure.ogg MusicBox.ogg
meri:/system/media/audio/ringtones $
從這裡可以發現 ringtones 目錄下是沒有 MI.ogg 這個檔案的,但卻存在一個 Mi.ogg 檔案,原來是檔名稱不匹配導致的!(應該是系統的一個 Bug)
既然找到了問題的導致原因,該如何解決呢?
檢視 RingtoneManager 可以發現還有一個介面:
RingtoneManager.getValidRingtoneUri(Context context)
對應的文件描述:
/**
* Returns a valid ringtone URI. No guarantees on which it returns. If it
* cannot find one, returns null. If it can only find one on external storage and the caller
* doesn't have the {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission,
* returns null.
*
**/
意思就是說該方法能夠確保返回一個有效的 uri,如果不能找到一個有效的 uri 則返回 null。
知道這個介面後可以這樣做:
Uri defaultRingtoneUri = RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE);
try {
mediaPlayer.setDataSource(context, defaultRingtoneUri);
mediaPlayer.prepare();
mediaPlayer.start();
} catch (IOException e) {
defaultRingtoneUri = RingtoneManager.getValidRingtoneUri(context);
mediaPlayer.setDataSource(context, defaultRingtoneUri);
mediaPlayer.prepare();
mediaPlayer.start();
}
這樣問題就解決了,即便播放系統鈴聲失敗也不至於什麼聲音都沒有。