質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Q&A

解決済

1回答

3776閲覧

MediaPlayerを用いた音楽プレイヤーでシャッフル再生を実現したい

wkt1227

総合スコア12

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

0グッド

0クリップ

投稿2019/07/06 17:53

前提・実現したいこと

デバイス内の音楽をシャッフル再生するアプリをMediaPlayerを用いて作りたいです。
現時点では、以下のような機能を持っています。

  • 最初に再生ボタン(playButton)を押すと、デバイス内のランダムな音楽が再生され、その後は一時停止、再生ボタンとして機能する。
  • 音楽名を表示するTextView(musicName)、再生位置を表示するSeekBar(positionBar)がある。

発生している問題・エラーメッセージ

音楽は再生できるのですが、2曲目以降の再生が上手くいきません。
曲が終わったら、ランダムに音楽を再生する、これを無限に繰り返すようにしたいです。

該当のソースコード

MainActivity.kt

kotlin

1package com.example.randommusicplayer 2 3import android.annotation.SuppressLint 4import android.media.MediaPlayer 5import androidx.appcompat.app.AppCompatActivity 6import android.os.Bundle 7import android.os.Handler 8import android.os.Message 9import kotlinx.android.synthetic.main.activity_main.* 10import android.widget.SeekBar 11 12 13 14class MainActivity : AppCompatActivity() { 15 16 private var totalTime: Int? = null 17 18 override fun onCreate(savedInstanceState: Bundle?) { 19 super.onCreate(savedInstanceState) 20 setContentView(R.layout.activity_main) 21 22 // ランダムに音楽情報を取得 23 val mItems = MusicItem.getItems(applicationContext) 24 val musicData = mItems.random() 25 26 // Media Playerの初期化 27 val mp = MediaPlayer.create(this, musicData.uri) 28 mp.isLooping = false 29 mp.seekTo(0) 30 totalTime = mp.duration 31 32 // 曲名の設定 33 musicName.text = musicData.title 34 35 // 再生位置 36 positionBar.max = totalTime as Int 37 positionBar.setOnSeekBarChangeListener( 38 object : SeekBar.OnSeekBarChangeListener { 39 override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { 40 if (fromUser) { 41 mp.seekTo(progress) 42 positionBar.progress = progress 43 } 44 } 45 46 override fun onStartTrackingTouch(seekBar: SeekBar) { 47 48 } 49 50 override fun onStopTrackingTouch(seekBar: SeekBar) { 51 52 } 53 } 54 ) 55 56 // Thread (positionBar、経過時間ラベル、残り時間ラベルを更新する) 57 Thread(Runnable { 58 while (mp != null) { 59 try { 60 val msg = Message() 61 msg.what = mp.currentPosition 62 handler.sendMessage(msg) 63 Thread.sleep(100) 64 } catch (e: InterruptedException) { 65 } 66 } 67 }).start() 68 69 // 曲が終了したら 70 mp.setOnCompletionListener { 71 playButton.setImageResource(R.drawable.ic_play_arrow_white_24dp) 72 } 73 74 playButton.setOnClickListener { 75 when(mp.isPlaying){ 76 // 再生中 77 true -> { 78 mp.pause() 79 playButton.setImageResource(R.drawable.ic_play_arrow_white_24dp) 80 81 } 82 // 停止中 83 false -> { 84 mp.start() 85 playButton.setImageResource(R.drawable.ic_pause_white_24dp) 86 } 87 } 88 } 89 } 90 91 private val handler = @SuppressLint("HandlerLeak") 92 object : Handler() { 93 override fun handleMessage(msg: Message) { 94 val currentPosition: Int = msg.what 95 96 // 再生位置を更新 97 positionBar.progress = currentPosition 98 99 // 経過時間ラベルを更新 100 val elapsedTime = createTimeLabel(currentPosition) 101 elapsedTimeLabel.text = elapsedTime 102 103 // 残り時間ラベルを更新 104 val remainingTime = createTimeLabel(totalTime!!.minus(currentPosition)) 105 remainingTimeLabel.text = "- $remainingTime" 106 } 107 } 108 109 fun createTimeLabel(time: Int): String { 110 var timeLabel: String 111 val min = time / 1000 / 60 112 val sec = time / 1000 % 60 113 114 timeLabel = "$min:" 115 if(sec < 10) timeLabel += "0" 116 timeLabel += sec.toString() 117 118 return timeLabel 119 } 120 121}

MusicItemは、デバイス内の音楽情報をリストにするためのクラスでここのサンプルコードをお借りしました。

試したこと

setOnCompletionListener内で、

// ランダムに音楽情報を取得 mItems = MusicItem.getItems(applicationContext) musicData = mItems.random() mp = MediaPlayer.create(this, musicData.uri) mp.seekTo(0) totalTime = mp.duration // 曲名の設定 musicName.text = musicData.title

このように書きましたが、2曲目しか再生されませんでした。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

kotlin

1mp = MediaPlayer.create(this, musicData.uri)

ここでmpを新しく生成した後、setOnCompletionListenerを呼んでいないのが原因ではないでしょうか?

改善案

上記のようなミスを防ぐためにも、次の曲の再生を開始する処理をメソッドに切り分けてしまうとスッキリまとまると思います。

kotlin

1private fun startNextTrack() { 2 // ランダムに音楽情報を取得 3 val mItems = MusicItem.getItems(applicationContext) 4 val musicData = mItems.random() 5 6 // Media Playerの初期化 7 val mp = MediaPlayer.create(this, musicData.uri) 8 mp.isLooping = false 9 mp.seekTo(0) 10 totalTime = mp.duration 11 12 ... 13 14 // 曲が終了したら 15 mp.setOnCompletionListener { 16 playButton.setImageResource(R.drawable.ic_play_arrow_white_24dp) 17 18 startNextTrack() // メソッドを呼び出せばOK 19 } 20}

投稿2019/07/08 13:10

kakajika

総合スコア3131

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

wkt1227

2019/07/10 14:30

回答ありがとうございます。ランダム再生自体は実現できましたが、音楽の再生をServiceに行わせる等、根本的にアプリの設計を見なおすつもりです。その際に、参考にできればさせてもらいます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問