つい最近 アプリを作っているとき・・・
音楽ファイルから
MediaPlayer に
setDataSource したい場面がありました。
そのとき、なぜか次みたいな 良く分からないエラー が出ます。
1 |
E/Class: setDataSource failed.: status=0x80000000 |
なにこれと思ったんですが、直し方は意外と簡単でした。
そこで この setDataSource でエラーが出てしまった時の対処法 をまとておきます。
このページの目次
MediaPlayer#setDataSource のエラーに遭遇した経緯
まずどういう場面でエラーに遭遇したのか、簡単に説明
自分の場合だとこういうケースでエラーが出てしまいました。
1.まず設定画面とかのActivityで音楽ピッカーを表示
1 2 3 4 5 |
Intent intent = new Intent(); intent.setType( "audio/*" ); intent.setAction( Intent.ACTION_PICK ); Intent chooser = Intent.createChooser( intent, "Select BGM" ); startActivityForResult( chooser, 12345 ); |
2.その結果(URI)を onActivityResult で取得
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@Override public void onActivityResult( int requestCode, int resultCode, Intent intent ) { super.onActivityResult( requestCode, resultCode, intent ); switch ( requestCode ) { case 12345: { Uri uri = intent.getData(); String musicPath = uri.toString(); /// 取得した音楽URIはアプリ内で保存...(略 break; } } } |
3.そして別ActivityでそのURIを setDataSource するという感じ
1 2 3 4 5 6 7 8 9 10 11 12 13 |
/// 音楽ファイルのパス(仮) String musicPath = "content://com.android.providers.downloads.documents/document/4230"; /// MediaPlayerインスタンス作成 MediaPlayer mp = MediaPlayer.create( this, R.raw.default ); try { mp.reset(); mp.setDataSource( musicPath ); } catch ( IOException e ) { /// エラーの後始末 } |
そして出てきたのが冒頭のエラー
1 |
E/Class: setDataSource failed.: status=0x80000000 |
原因が分からなくて数時間くらい格闘したんですが、ようやく解決策らしきものが見つかりました。
MediaPlayer#setDataSorce のエラーの原因と解決策
主に次の2点を疑ったらエラーが発生しなくなります。(自分の場合)
1.ACTION_PICK の代わりに ACTION_OPEN_DOCUMENT を使う
まず原因として考えられるのが ACTION_GET_CONTENT を使ってるから
ACTION_PICK を使ってる場合も同じです。
▼ リファレンスでの ACTION_GET_CONTENT の説明
アプリでデータの読み取りとインポートのみを行う場合は、ACTION_GET_CONTENT を使用します。この方法を使用すると、アプリは、画像ファイルなどのデータのコピーをインポートします。
引用元 : https://developer.android.com/guide/topics/providers/document-provider.html#client
単純に読み書きするだけの用途(一時的)に使うのが適してる模様
今回の場合、別Activityから音楽ファイルを参照する目的で使っていたので、エラーの温床になっていたらしいです。これは盲点でした。
そこで代わりに ACTION_OPEN_DOCUMENT を使うことにします。
▼ ACTION_OPEN_DOCUMENT についての説明
アプリからドキュメント プロバイダが所有するドキュメントへの、長期間の固定アクセスを可能にするには、ACTION_OPEN_DOCUMENT を使用します。ドキュメント プロバイダに格納されている画像をユーザーが編集するための、写真編集アプリなどの例が挙げられます。
引用元 : https://developer.android.com/guide/topics/providers/document-provider.html#client
大事なのは「長期間の固定アクセスを可能にする」という部分
この説明の通り、長期的に参照するファイルはコチラを使うのが良さそうです。
例えばBGMプレイヤーとか再生リスト系のアプリとか・・・
ということで、音楽ピッカーのコードを次のように置き換え ました。
1 2 3 4 5 |
Intent intent = new Intent(); intent.setType( "audio/*" ); intent.setAction( Intent.ACTION_OPEN_DOCUMENT ); Intent chooser = Intent.createChooser( intent, "Select BGM" ); startActivityForResult( chooser, 12345 ); |
単純に setAction に渡してたアクションタイプを変えただけ
とはいえ「これでエラー解決!!」とはいかず、まだエラーが出てます・・・ orz
2.setDataSource の引数にパスではなくURIを渡す
実はエラーが出ていた原因はもう1つありました。
それは setDataSource に文字列でパスを渡してたこと
つまり先ほどの例なら、こういうコード
1 2 |
/// ▼ これが原因? mp.setDataSource( musicPath ); |
まあ content:// から始まるURIを渡してたので、エラーが出て当然と言えば当然ですね。
そこで文字列ではなく、URIを渡すことにしました。
▼ それが次のコード
1 2 3 4 5 6 7 8 9 10 11 12 |
String musicPath = "content://com.android.providers.downloads.documents/document/4230"; MediaPlayer mp = MediaPlayer.create( this, R.raw.default ); try { mp.reset(); uri = Uri.parse( musicPath ); mp.setDataSource( this, uri ); } catch ( IOException e ) { /// エラーの後始末 } |
まず Uri.patse( musicPath ) でパス文字列をUriオブジェクトに変換
そのあと setDataSource にURIとして音楽ファイルを設定しているだけ
これで無事エラーが消えて、音声が再生できるようになりました。めでたしめでたし・・
ここまでのまとめ
以上、MediaPlayer#setSourceData でエラーが出るときの対処法でした。
音楽ピッカーに渡すアクションタイプを ACTION_OPEN_DOCUMENT に変更し、パスを文字列ではなくURIとして渡せば直るかもしれません。
参考までに対処法を残しておきます。