web-dev-qa-db-ja.com

Mediaplayerの進捗状況の更新がシークバーにスムーズでない?

私はレコーダーとプレーヤーを備えたアプリに取り組んでいます。記録された.wavファイルを再生するためにmediaplayerを使用していますが、その間にシークバーに更新したいと考えています。すべてが正常に動作していますが、私の問題は、シークバーへのメディアプレーヤーの進行状況の更新がスムーズに行われていないことです。小さなファイルを再生している場合、シークバーの親指が数秒または間でジャンプします。

誰かがシークバーの進行状況をスムーズに求めるための回避策を教えてくれますか?私のコードを以下に示します。

    mediaPlayerIntiate();
    mediaPlayerSetSource();
    mMediaPlayer.start();
    task = new TimerTask() {
                @Override
                public void run() {
                    Graphbar.post(new Runnable() {
                        @Override
                        public void run() {

                            if (mMediaPlayer != null) {

                                if (playButtonState == MediaMode.PLAY) {
                                    if (mMediaPlayer.isPlaying()) {
                                        Graphbar.setProgress(mMediaPlayer
                                                .getCurrentPosition());
                                        mediaPlayerUpdateTimer(mMediaPlayer
                                                .getCurrentPosition());
                                        enableRewindandForward();
                                    }
                                }

                            }

                        }
                    });
                }
            };
            timer = new Timer();
            timer.schedule(task, 0, 8);
16
Sreedev R

mMediaPlayer.getCurrentPosition()現在の時間をミリ秒で返し、これを最大容量が100であるSeekbarに更新します。ファイルの長さと100で1つの数式を作成します。この関数を試してください

    MediaPlayer mMediaPlayer = new MediaPlayer();
    final SeekBar mSeelBar = new SeekBar(this);
    final int duration = mMediaPlayer.getDuration();
    final int amoungToupdate = duration / 100;
    Timer mTimer = new Timer();
    mTimer.schedule(new TimerTask() {

        @Override
        public void run() {
            runOnUiThread(new Runnable() {

                @Override
                public void run() {
                    if (!(amoungToupdate * mSeelBar.getProgress() >= duration)) {
                        int p = mSeelBar.getProgress();
                        p += 1;
                        mSeelBar.setProgress(p);
                    }
                }
            });
        };
    }, amoungToupdate);

このプロセスは、メディアプレーヤーが再生を開始するときに呼び出す必要があります。内部

mediaPlayer.setOnPreparedListener(new OnPreparedListener(){

    @Override
    public void onPrepared(MediaPlayer mp) {
    **// call here**
});

更新

秒単位で125回の更新は、行うべきではありません。 SeekBarを更新する間隔を増やしてください。 NullPointerのコメントを読んだ後、これを追加します

19
Tofeeq Ahmad

seekbar.setProgress()はintのみを受け入れます。したがって、私たちのほとんどは、経過した割合をこのメソッドに渡す傾向があります。ただし、よりスムーズな進行が必要な場合は、ミリ秒単位の期間をMAXとして使用できます。次に、シークバーの進行をミリ秒ごとに更新します。以下は例であり、Androidの携帯電話には60 fps(フレーム/秒)のリフレッシュレートが付属しているため、ほぼ毎回、15ミリ秒ごとに更新しています。

    try{
        mediaPlayer.start();
        seekbar.setProgress(0);
        seekbar.setMax(mediaPlayer.getDuration());

        // Updating progress bar
        seekHandler.postDelayed(updateSeekBar, 15);
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    } catch (IllegalStateException e) {
        e.printStackTrace();
    }

/**
 * Background Runnable thread
 * */
private Runnable updateSeekBar = new Runnable() {
    public void run() {
        long totalDuration = mediaPlayer.getDuration();
        long currentDuration = mediaPlayer.getCurrentPosition();

        // Displaying Total Duration time
        remaining.setText(""+ milliSecondsToTimer(totalDuration-currentDuration));
        // Displaying time completed playing
        elapsed.setText(""+ milliSecondsToTimer(currentDuration));

        // Updating progress bar
        seekbar.setProgress((int)currentDuration);

        // Call this thread again after 15 milliseconds => ~ 1000/60fps
        seekHandler.postDelayed(this, 15);
    }
};

/**
 * Function to convert milliseconds time to
 * Timer Format
 * Hours:Minutes:Seconds
 * */
public String milliSecondsToTimer(long milliseconds){
    String finalTimerString = "";
    String secondsString = "";

    // Convert total duration into time
    int hours = (int)( milliseconds / (1000*60*60));
    int minutes = (int)(milliseconds % (1000*60*60)) / (1000*60);
    int seconds = (int) ((milliseconds % (1000*60*60)) % (1000*60) / 1000);
    // Add hours if there
    if(hours > 0){
        finalTimerString = hours + ":";
    }

    // Prepending 0 to seconds if it is one digit
    if(seconds < 10) {
        secondsString = "0" + seconds;
    }else {
        secondsString = "" + seconds;
    }

    finalTimerString = finalTimerString + minutes + ":" + secondsString;

    // return timer string
    return finalTimerString;
}
5
Hamzeen Hameem
player.prepare(); // or start()

ScheduledExecutorService service = Executors.newScheduledThreadPool(1);
service.scheduleWithFixedDelay(new Runnable()
{
  @Override
  public void run()
  {
    progressBar.setProgress(player.getCurrentPosition());
  }
}, 1, 1, TimeUnit.MICROSECONDS);
4
susemi99

これがシークバーの処理方法です。

        mediaPlayer.setOnPreparedListener(new OnPreparedListener(){

        @Override
        public void onPrepared(MediaPlayer mp) {
            mediaPlayer.start();
            new SeekBarHandler().execute();
    });

これで、次のようにシークバーを処理するSeekBarHandlerという非同期タスクがあります。

    public class SeekBarHandler extends AsyncTask<Void, Void, Void> {

@Override
protected void onPostExecute(Void result) {
    Log.d("##########Seek Bar Handler ################","###################Destroyed##################");
    super.onPostExecute(result);
}

@Override
protected void onProgressUpdate(Void... values) {
    seekBar.setProgress(mediaPlayer.getCurrentPosition());
    super.onProgressUpdate(values);
}

@Override
protected Void doInBackground(Void... arg0) {
    while(mediaPlayer.isPlaying()&&isViewOn==true) {
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    onProgressUpdate();
    }
    return null;
}

    }

OnPauseで、ユーザーがシークバーを表示できない場合にスレッドを継続することは意味がないため、AsyncTaskを終了します。

    protected void onPause() {
    isViewOn=false;
    super.onPause();
    }

そしてonResumeで私はこのようにAsyncTaskAgainを開始します

    protected void onResume() {
    isViewOn=true;
    new SeekBarHandler().execute();
    super.onResume();
    }

ご覧のとおり、ブールフラグisViewOnを使用して、ビューがオンになっているかどうかを確認し、シークバーを処理します。

4
Peshal

発生している問題は、AndroidのSeekBarの設計/実装方法に関係しています。これは非常にうまく機能しますが、使用されるセグメントの組み合わせ(つまり、seekbar.setMax(int))とハンドラーの遅延時間によって制限されます。

そうは言っても、ハンドラの代わりにViewPropertyAnimatorsを使用する独自のSmoothSeekBarを作成するためにSeekBarをサブクラス化しました。

ここで確認してください: https://github.com/Indatus/Android-SmoothSeekBar

0
jonstaff