简体   繁体   中英

Android audio seekbar delay

Just started to learn Java and I'm currently learning some media-basic stuff. I created a little app (which plays a music file) with a volume controller seek bar which works fine, a play and a stop button which also work fine. I managed to get till that point when music plays, the progress seek bar updates and moves to the right as it needs to do when the song is playing. When want to add the code to actually be able to change the progress of the music, I get a pause (delay) every time the seek is updated (every 1000 milliseconds / 1 sec). If I add the

mplayer.seekTo(progress);

to the code, I get the music delay every time the seek bar updates (every second).

Here is my code:

package com.dionisie.sounddemo;

import android.content.Context; import android.media.AudioManager;
import android.support.v7.app.AppCompatActivity; import
android.os.Bundle; import android.media.MediaPlayer; import
android.view.View; import android.widget.SeekBar; import
android.widget.SeekBar.OnSeekBarChangeListener; import
android.util.Log;

import java.util.Timer; import java.util.TimerTask;

public class MainActivity extends AppCompatActivity {

    MediaPlayer mplayer;

    AudioManager audioManager;

    public void playAudio(View view) {
        mplayer.start();
    }


    public void pauseAudio(View view) {
        mplayer.pause();
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mplayer = MediaPlayer.create(this, R.raw.joanna);

        audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
        int curVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);

        SeekBar volumeControl = (SeekBar) findViewById(R.id.seekBar);
        volumeControl.setMax(maxVolume);
        volumeControl.setProgress(curVolume);

        volumeControl.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

                audioManager.setStreamVolume(audioManager.STREAM_MUSIC, progress, 0);

            }
        });


        final SeekBar scrubber = (SeekBar) findViewById(R.id.scrubber);

        scrubber.setMax(mplayer.getDuration());

        new Timer().scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                scrubber.setProgress(mplayer.getCurrentPosition());
            }
        }, 0, 1000);

        scrubber.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                mplayer.seekTo(progress);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });

    } }

First thing First, define a public int and a public boolean int save, boolean flag

change your setOnSeekBarChangeListener to this

 volumeControl.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            save = progress;

        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
            mplayer.pause();
            flag = true;


        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            mplayer.seekTo(save);
            mplayer.start();
            flag = false;
        }
    });

And then change your Timer().scheduleAtFixedRate to this (added an if statement)

new Timer().scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {

            if (!flag) 
                scrubber.setProgress(mplayer.getCurrentPosition());

        }
    },0 ,1000);

and DONE! Hope to understand the reason of changing. But if you didn't just ask.

Function "setProgress" makes a change in the Seek bar and this is called every x milliseconds by Timer. Any change made in the seek bar will be captured by "seekbarchangeListener". In change seekbarChangeListener we have added a seekTo function which will move the music by x+dx seconds. This additional dx seconds added due to delay that causes the lag effect.

Below implementation checks for the isSongRunning boolean so that seekTo is not done if there is a change in Seekbar from Timer if the change is done due to the movement in the seekbar this will be false.

final SeekBar sngbar = (SeekBar) findViewById(R.id.player); sngbar.setMax(song.getDuration());

    new Timer().scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            isSongRunning = true;
            sngbar.setProgress(song.getCurrentPosition());

        }
    }, 0, 100);


    sngbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {

        @Override
        public void onProgressChanged(SeekBar seekBar, int sngchg, boolean b) {
            if(!isSongRunning){
                song.seekTo(sngchg);
            }else
            {
                isSongRunning = !isSongRunning;
            }

        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {

        }
    });

Also you can increase the x milliseconds in timer to 10000, the lag will be very minimal and is not identified that easily. But by doing this way, the reflection of the seek bar status will not be quick.

In the onProgressChanged() , write the code as:

if(fromUser)
    mplayer.seekTo(progress);

Thus the seekTo will get triggered only when user does, and not because of the Timer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM