简体   繁体   English

Android-SeekBar和MediaPlayer

[英]Android - SeekBar and MediaPlayer

I needed to connect my SeekBar with my MediaPlayer in my App. 我需要在我的App中将SeekBarMediaPlayer连接起来。

I set up the SeekBar via xml like this: 我通过xml这样设置了SeekBar:

<SeekBar
        android:id="@+id/song_seekbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"/>

and followed this SO answer to implement it. 并按照这个答案来实现它。

This is my code: 这是我的代码:

public class Song_main extends AppCompatActivity {
private final int SONG_REQUEST_CODE = 1;

private Uri song;
private TextView selectSong;
private SeekBar seekBar;
private Handler handler;
private MediaPlayer mediaPlayer;


private boolean repeatPressedTwice = false;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.app_bar_song_main);

    Toolbar toolbar = (Toolbar) findViewById(R.id.song_main_toolbar);
    setSupportActionBar(toolbar);
    getSupportActionBar().setDisplayShowTitleEnabled(false);

    seekBar = (SeekBar) findViewById(R.id.song_seekbar);
    handler = new Handler();

    notSelected();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.song, menu);

    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();

    if (id == R.id.song_plus) {
        Intent selectIntent = new Intent(Intent.ACTION_GET_CONTENT);
        selectIntent.setType("audio/*");
        startActivityForResult(selectIntent, SONG_REQUEST_CODE);
    }

    return true;
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == SONG_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
        if ((data != null) && (data.getData()!=null)) {
            song = data.getData();
            setup();
        }
    }
}

private void notSelected() {
    selectSong = (TextView) findViewById(R.id.select_song_textview);
    selectSong.setText(getResources().getString(R.string.song_not_selected));
}

public void onPlayButtonClicked(View v) {
    ImageButton pb = (ImageButton) findViewById(R.id.song_play_button);
    if (!mediaPlayer.isPlaying()) {
        mediaPlayer.start();
        pb.setImageResource(R.drawable.pause);

        updateSeekBar();

    } else {
        mediaPlayer.pause();
        pb.setImageResource(R.drawable.ic_play_arrow_white_24dp);
    }
}

public void onControlsClicked(View v) {
    if (v.getId() == R.id.fast_forward) {
        int pos = mediaPlayer.getCurrentPosition();
        pos += 1500;
        mediaPlayer.seekTo(pos);
    }
    else if (v.getId() == R.id.fast_backward) {
        int pos = mediaPlayer.getCurrentPosition();
        pos -= 1500;
        mediaPlayer.seekTo(pos);
    }
    else if (v.getId() == R.id.skip_backward) {
        mediaPlayer.seekTo(0);
    }
}

public void onRepeatClicked(View v) {
    if (!repeatPressedTwice) {
        // TODO: change visual color of repeat button
        mediaPlayer.setLooping(true);
        Toast.makeText(this, "repeat enabled", Toast.LENGTH_SHORT).show();
        repeatPressedTwice = true;
    } else {
        mediaPlayer.setLooping(false);
    }

}

private void setup() {
    /* the song has been select setup the interface */


    /* displays song name in title */
    TextView titleView = (TextView) findViewById(R.id.song_appbar_title);
    String songName;

    ContentResolver contentResolver = this.getContentResolver();
    Cursor cursor = contentResolver.query(song, null, null, null, null);

    if (cursor != null && cursor.moveToFirst()) {
        songName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
        titleView.setText(songName);
    }


    /* removes the notSelected String */
    selectSong.setVisibility(View.GONE);

    /* setup media player */
    mediaPlayer = new MediaPlayer();
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    try {
        mediaPlayer.setDataSource(getApplicationContext(), song);
        mediaPlayer.prepareAsync();
    } catch (IOException e) {
        Toast.makeText(this, "file not found", Toast.LENGTH_SHORT).show();
    }

    mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mp) {
            /* show media player layout */
            RelativeLayout mpl = (RelativeLayout) findViewById(R.id.media_player_layout);
            mpl.setVisibility(View.VISIBLE);

            mediaPlayer.start();
            ImageButton pb = (ImageButton) findViewById(R.id.song_play_button);
            pb.setImageResource(R.drawable.pause);

        }
    });

    mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mp) {
            ImageButton pb = (ImageButton) findViewById(R.id.song_play_button);
            pb.setImageResource(R.drawable.ic_play_arrow_white_24dp);
        }
    });



    seekBar = (SeekBar) findViewById(R.id.song_seekbar);
    seekBar.setMax(mediaPlayer.getDuration()); 

    updateSeekBar();


}

private void updateSeekBar() {
    seekBar.setProgress(mediaPlayer.getCurrentPosition()/1000);
    handler.postDelayed(runnable, 1000);
}

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        updateSeekBar();
    }
};


@Override
public void onStop() {
    super.onStop();
    if (mediaPlayer!=null)
        mediaPlayer.stop();
}
}

The process starts from the onOptionsItemSelected method. 该过程从onOptionsItemSelected方法开始。

The seekBar behaves correctly, it increments every second. seekBar的行为正确,每秒增加一次。 The problem now is that it finishes way before the song finishes. 现在的问题是,它在歌曲完成之前就完成了。

I tried adding 我尝试添加

seekBar.setMax(mediaPlayer.getDuration());

in the setup method, but that causes the bar not to move at all. setup方法中,但这会导致栏完全不移动。

You need to define separate Runnable and trigger it every x miliseconds (depends on you) once MediaPlayer starts. 您需要定义单独的Runnable并在MediaPlayer启动后每隔x毫秒(取决于您)触发一次。

Define a function updateSeekbar like, 定义一个函数updateSeekbar

private void updateSeekBar() {
    audioSeek.setProgress(player.getCurrentPosition());
    txtCurrentTime.setText(milliSecondsToTimer(player.getCurrentPosition()));
    seekHandler.postDelayed(runnable, 50);
}

And Runnable Runnable

Runnable runnable = new Runnable() {
    @Override
    public void run() {
        updateSeekBar();
    }
};

Now you just have to call updateSeekbar once when playing starts. 现在,您只需要在播放开始时调用一次updateSeekbar In your case: 在您的情况下:

public void onPlayButtonClicked(View v) {
    ImageButton pb = (ImageButton) findViewById(R.id.song_play_button);
    if (!mediaPlayer.isPlaying()) {
        mediaPlayer.start();
        pb.setImageResource(R.drawable.pause);

        updateSeekBar();

    } else {
        mediaPlayer.pause();
        pb.setImageResource(R.drawable.ic_play_arrow_white_24dp);
    }
}

FYI FYI

Function milliSecondsToTimer works as follows 函数milliSecondsToTimer工作原理如下

private 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;
}

UPDATE UPDATE

You have called setMax at the wrong place. 您在错误的位置调用了setMax Update setup() function as follows 更新setup()函数,如下所示

private void setup() {
    /* the song has been select setup the interface */
    /* displays song name in title */
    TextView titleView = (TextView) findViewById(R.id.song_appbar_title);
    String songName;

    ContentResolver contentResolver = this.getContentResolver();
    Cursor cursor = contentResolver.query(song, null, null, null, null);

    if (cursor != null && cursor.moveToFirst()) {
        songName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
        titleView.setText(songName);
    }


    /* removes the notSelected String */
    selectSong.setVisibility(View.GONE);

    /* setup media player */
    mediaPlayer = new MediaPlayer();
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    try {
        mediaPlayer.setDataSource(getApplicationContext(), song);
        mediaPlayer.prepareAsync();
    } catch (IOException e) {
        Toast.makeText(this, "file not found", Toast.LENGTH_SHORT).show();
    }

    mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
        @Override
        public void onPrepared(MediaPlayer mp) {
        /* show media player layout */
            seekBar.setMax(mediaPlayer.getDuration());

            RelativeLayout mpl = (RelativeLayout) findViewById(R.id.media_player_layout);
            mpl.setVisibility(View.VISIBLE);
            mediaPlayer.start();

            updateSeekBar();


            ImageButton pb = (ImageButton) findViewById(R.id.song_play_button);
            pb.setImageResource(R.drawable.pause);

        }
    });

    mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mp) {
            ImageButton pb = (ImageButton) findViewById(R.id.song_play_button);
            pb.setImageResource(R.drawable.ic_play_arrow_white_24dp);
        }
    });

}

you need to update your Seek bar when you play a song 播放歌曲时需要更新搜索栏

public void updateProgressBar() {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mHandler.postDelayed(mUpdateTimeTask, 100);
            }
        });

    }  

Below Runnable method to update seekbar 下面的Runnable方法来更新seekbar

private Runnable mUpdateTimeTask = new Runnable() {
        public void run() {
            if (MusicService.isRunning()) {
                duration = MusicService.getDur();
                long currSongPosition = MusicService.getPosn();
                totTime.setText(Utility.milliSecondsToTimer(duration));
                fromTime.setText(Utility.milliSecondsToTimer(currSongPosition));
                int progress = Utility.getProgressPercentage(currSongPosition, duration);
            songProgressBar.setProgress(progress);
            updateProgressBar();
        }
    }
};

Using this below function you can get progress percentage from song current position and song duration 使用以下功能,您可以从歌曲当前位置和歌曲持续时间获得进度百分比

 public static int getProgressPercentage(long currentDuration, long totalDuration) {
        Double percentage;
        long currentSeconds = (int) (currentDuration / 1000);
        long totalSeconds = (int) (totalDuration / 1000);
        percentage = (((double) currentSeconds) / totalSeconds) * 100;
        return percentage.intValue();
    }

You have implement OnSeekBarChangeListener and in onCreate() add the below line:- 您已经实现了OnSeekBarChangeListener并在onCreate()添加以下行:

seekBar = (SeekBar) findViewById(R.id.seekBar);

And override the onProgressChanged() method , in this method you can set the progress in the seekbar using the below line: 并覆盖onProgressChanged()方法,在此方法中,您可以使用以下行在搜寻栏中设置进度:

mPlayer.seekTo(progress); 
seekBar.setProgress(progress);

or 要么

After you initialise your MediaPlayer and for example press the play button, you should create an handler and post runnable so you can update your SeekBar (in the UI thread itself) with the current position of your MediaPlayer like this : 在初始化MediaPlayer并例如按下播放按钮之后,您应该创建一个处理程序并发布可运行文件,以便可以使用MediaPlayer的当前位置来更新SeekBar(在UI线程本身中),如下所示:

private Handler mHandler = new Handler();
//Make sure you update Seekbar on UI thread
MainActivity.this.runOnUiThread(new Runnable(){
    @Override
    public void run() {
        if(mMediaPlayer != null){
            int mCurrentPosition = mMediaPlayer.getCurrentPosition() / 1000;
            mSeekBar.setProgress(mCurrentPosition);
        }
    mHandler.postDelayed(this, 1000);
    }
});

and update that value every second. 并每秒更新一次该值。

If you need to update the MediaPlayer's position while user drag your SeekBar you should add OnSeekBarChangeListener to your SeekBar and do it there : 如果在用户拖动SeekBar时需要更新MediaPlayer的位置,则应将OnSeekBarChangeListener添加到SeekBar并在其中进行操作:

mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
     @Override
     public void onStopTrackingTouch(SeekBar seekBar) {

     }
     @Override
     public void onStartTrackingTouch(SeekBar seekBar) {

     }
     @Override
     public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
         if(mMediaPlayer != null && fromUser){
             mMediaPlayer.seekTo(progress * 1000);
     }
  }
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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