带有进度条的Android 音乐播放器

时间:2020-02-23 14:29:04  来源:igfitidea点击:

在本教程中,我们将使用MediaPlayer类在我们的Android应用程序中实现基本的音频播放器。
我们将添加播放/停止功能,还允许用户使用SeekBar更改歌曲的位置。

Android MediaPlayer

MediaPlayer类用于播放音频和视频文件。
我们将使用的MediaPlayer类的常见方法是:

  • 开始()

  • 停()

  • release()–防止内存泄漏。

  • seekTo(position)–将与SeekBar一起使用

  • isPlaying()–让我们知道歌曲是否正在播放。

  • getDuration()–用于获取总持续时间。
    使用此方法,我们将了解SeekBar的上限。
    此函数返回以毫秒为单位的持续时间

  • setDataSource(FileDescriptor fd)–用于设置要播放的文件。

  • setVolume(float leftVolume,float rightVolume)–用于设置音量。
    取值范围是0到1。

我们将播放存储在Android Studio项目资产文件夹中的mp3文件。

从Assets文件夹中获取声音资产文件

AssetFileDescriptor descriptor = getAssets().openFd("filename");
              mediaPlayer.setDataSource(descriptor.getFileDescriptor(), descriptor.getStartOffset(), descriptor.getLength());
              descriptor.close();

为了创建一个播放音频并允许您更改当前歌曲轨道位置的应用程序,我们需要实现三件事:

  • 媒体播放器

  • SeekBar With Text –用拇指显示当前的进度时间。

  • 可运行线程–更新Seekbar。

项目结构

在build.gradle中添加以下依赖项:

implementation 'com.android.support:design:28.0.0-alpha3'

代码

下面给出了activity_main.xml的代码:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
  xmlns:app="https://schemas.android.com/apk/res-auto"
  xmlns:tools="https://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:layout_gravity="center"
  android:gravity="center"
  android:layout_margin="16dp"
  android:orientation="vertical"
  tools:context=".MainActivity">

  <TextView
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:gravity="center"
      android:text="PLAY/STOP SONG.\nSCRUB WITH SEEKBAR"
      android:textStyle="bold" 

  <SeekBar
      android:id="@+id/seekbar"
      android:layout_margin="16dp"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:layout_gravity="center" 

  <TextView
      android:id="@+id/textView"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content" 

  <android.support.design.widget.FloatingActionButton
      android:id="@+id/button"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:layout_margin="16dp"
      android:src="@android:drawable/ic_media_play"
      android:text="PLAY SOUND" 

</LinearLayout>

我们添加了一个FloatingActionButon,单击该按钮即可播放/停止。

MainActivity.java类的代码如下:

package com.theitroad.androidmediaplayersong;

import android.content.res.AssetFileDescriptor;
import android.media.MediaPlayer;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.SeekBar;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity implements Runnable {

  MediaPlayer mediaPlayer = new MediaPlayer();
  SeekBar seekBar;
  boolean wasPlaying = false;
  FloatingActionButton fab;

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

      fab = findViewById(R.id.button);

      fab.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View view) {
              playSong();
          }
      });

      final TextView seekBarHint = findViewById(R.id.textView);

      seekBar = findViewById(R.id.seekbar);

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

              seekBarHint.setVisibility(View.VISIBLE);
          }

          @Override
          public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
              seekBarHint.setVisibility(View.VISIBLE);
              int x = (int) Math.ceil(progress/1000f);

              if (x  0 && mediaPlayer != null && !mediaPlayer.isPlaying()) {
                  clearMediaPlayer();
                  fab.setImageDrawable(ContextCompat.getDrawable(MainActivity.this, android.R.drawable.ic_media_play));
                  MainActivity.this.seekBar.setProgress(0);
              }

          }

          @Override
          public void onStopTrackingTouch(SeekBar seekBar) {

              if (mediaPlayer != null && mediaPlayer.isPlaying()) {
                  mediaPlayer.seekTo(seekBar.getProgress());
              }
          }
      });
  }

  public void playSong() {

      try {

          if (mediaPlayer != null && mediaPlayer.isPlaying()) {
              clearMediaPlayer();
              seekBar.setProgress(0);
              wasPlaying = true;
              fab.setImageDrawable(ContextCompat.getDrawable(MainActivity.this, android.R.drawable.ic_media_play));
          }

          if (!wasPlaying) {

              if (mediaPlayer == null) {
                  mediaPlayer = new MediaPlayer();
              }

              fab.setImageDrawable(ContextCompat.getDrawable(MainActivity.this, android.R.drawable.ic_media_pause));

              AssetFileDescriptor descriptor = getAssets().openFd("suits.mp3");
              mediaPlayer.setDataSource(descriptor.getFileDescriptor(), descriptor.getStartOffset(), descriptor.getLength());
              descriptor.close();

              mediaPlayer.prepare();
              mediaPlayer.setVolume(0.5f, 0.5f);
              mediaPlayer.setLooping(false);
              seekBar.setMax(mediaPlayer.getDuration());

              mediaPlayer.start();
              new Thread(this).start();

          }

          wasPlaying = false;
      } catch (Exception e) {
          e.printStackTrace();

      }
  }

  public void run() {

      int currentPosition = mediaPlayer.getCurrentPosition();
      int total = mediaPlayer.getDuration();

      while (mediaPlayer != null && mediaPlayer.isPlaying() && currentPosition < total) {
          try {
              Thread.sleep(1000);
              currentPosition = mediaPlayer.getCurrentPosition();
          } catch (InterruptedException e) {
              return;
          } catch (Exception e) {
              return;
          }

          seekBar.setProgress(currentPosition);

      }
  }

  @Override
  protected void onDestroy() {
      super.onDestroy();
      clearMediaPlayer();
  }

  private void clearMediaPlayer() {
      mediaPlayer.stop();
      mediaPlayer.release();
      mediaPlayer = null;
  }
}

在上面单击FloatingActionButton的代码中,将触发playSong函数,在该函数中,我们停止播放歌曲并每隔第二次重置MediaPlayer和FloatingActionButton图标。

调用mediaPlayer.prepare()之后,该歌曲的详细信息即可使用。
现在,我们可以获取持续时间并将其设置在SeekBar的最大位置上。

将setLoooping设置为false可以阻止歌曲无限播放,直到被用户停止为止。

我们启动触发" run"方法的线程,该方法是我们已实现的Runnable接口的一部分。

在run方法内部,我们每秒更新一次进度,这会触发SeekBar侦听器的onProgressChanged方法。

在侦听器内部,我们已将TextView偏移设置为SeekBar的拇指下方。
我们通过将毫秒转换为秒来设置持续时间。

移动搜索列时,将触发相同的方法。
当用户停止擦拭SeekBar时,会触发onStopTrackingTouch,其中将使用" seekTo"方法更新MediaPlayer实例上的歌曲位置。

歌曲完成后,我们将SeekBar的位置更新回初始位置,并清除MediaPlayer实例。