Android初级,MediaPlayer播放音乐,进度条滑动及唱片转动功能实现

最近在做仿网易云音乐播放器的实训项目,学习完后写此博客,一方面巩固自己理解,一方面方便各位浏览。
读完本文你将了解到:

  • 如何利用MediaPlayer播放音乐
  • 如何设置音乐进度条并实现自动滚动及手动定位
  • 如何实现唱片转动功能

1.效果图

Android初级,MediaPlayer播放音乐,进度条滑动及唱片转动功能实现_第1张图片
Android初级,MediaPlayer播放音乐,进度条滑动及唱片转动功能实现_第2张图片

2.代码如下

Layout

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    android:orientation="vertical">
//设置背景图片
    <ImageView
        android:id="@+id/listen_background_iv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"
        android:src="@mipmap/img1" />

    <RelativeLayout
        android:id="@+id/listen_rl"
        android:layout_width="match_parent"
        android:layout_height="70dp"
        android:layout_weight="1">
//设置返回按钮图片
        <ImageView
            android:id="@+id/listen_back1_iv"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_alignParentStart="true"
            android:layout_centerVertical="true"
            android:layout_marginLeft="5dp"
            android:src="@mipmap/back1" />
//设置歌曲名
        <TextView
            android:id="@+id/listen_title_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="15dp"
            android:layout_marginTop="8dp"
            android:layout_toRightOf="@id/listen_back1_iv"
            android:text="成都"
            android:textColor="#f9f7f7"
            android:textSize="20sp" />
//设置歌手名
        <TextView
            android:id="@+id/listen_artist_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignStart="@id/listen_title_tv"
            android:layout_below="@id/listen_title_tv"
            android:layout_marginTop="5dp"
            android:text="赵雷-"
            android:textColor="#aeabab"
            android:textSize="15sp" />
//设置专辑名
        <TextView
            android:id="@+id/listen_album_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignTop="@id/listen_artist_tv"
            android:layout_toRightOf="@id/listen_artist_tv"
            android:text="成都"
            android:textColor="#aeabab"
            android:textSize="15sp" />
//设置“分享”按钮(本代码中未实现)
        <ImageView
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_alignParentEnd="true"
            android:layout_centerVertical="true"
            android:layout_marginRight="15dp"
            android:src="@mipmap/share" />
//设置布局间的线
        <View
            android:layout_width="match_parent"
            android:layout_height="0.5dp"
            android:layout_below="@id/listen_artist_tv"
            android:background="#bababa" />
    RelativeLayout>

//设置唱片圆盘
    <ImageView
        android:id="@+id/listen_changpian_img"
        android:layout_width="250dp"
        android:layout_height="250dp"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"

        android:src="@mipmap/play_page_disc" />
//设置圆盘上的指针
    <ImageView
        android:id="@+id/listen_zhizhen_iv"
        android:layout_width="100dp"
        android:layout_height="150dp"
        android:layout_below="@id/listen_rl"
        android:layout_centerHorizontal="true"
        android:src="@mipmap/play_page_needle" />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:layout_marginBottom="15dp">

        <RelativeLayout
            android:id="@+id/listen_play"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="0dp">

//设置“暂停”
            <ImageView
                android:id="@+id/listen_pause1_img"
                android:layout_width="60dp"
                android:layout_height="60dp"
                android:layout_centerHorizontal="true"
                android:layout_centerVertical="true"
                android:layout_marginTop="10dp"
                android:src="@mipmap/icon_music_circle_pause" />
//设置“上一首”
            <ImageView
                android:id="@+id/listen_back_img"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:layout_centerVertical="true"
                android:layout_marginLeft="30dp"
                android:layout_marginRight="30dp"
                android:layout_toLeftOf="@id/listen_pause1_img"
                android:src="@mipmap/back_w" />

//设置下一首
            <ImageView
                android:id="@+id/listen_next_img"
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:layout_centerVertical="true"
                android:layout_marginLeft="30dp"
                android:layout_toRightOf="@id/listen_pause1_img"
                android:src="@mipmap/next_w" />

        RelativeLayout>



        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_above="@id/listen_play"
            android:layout_marginBottom="10dp"
            android:orientation="horizontal"
            android:paddingLeft="10dp"
            android:paddingRight="10dp">
//设置“当前歌曲时间”
            <TextView
                android:id="@+id/listen_current_tv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="00:00" />
//设置“进度条”
            <SeekBar
                android:id="@+id/listen_jindutiao_sb"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1" />
//设置“歌曲总时长”
            <TextView
                android:id="@+id/listen_length_tv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="02:30" />

        LinearLayout>


    RelativeLayout>
RelativeLayout>

MusicActivity

首先对需要用到的控件进行定义:

    private ImageView backIv;
    private ImageView nextIv;//"下一首"
    private ImageView discsmap;//"唱片"
    private ImageView pauseIv;//“暂停”
    private MediaPlayer mediaPlayer;//"MediaPlayer"
    private ObjectAnimator animator;//运用ObjectAnimator实现转动
    private TextView currentTv;//"当前时间"
    private TextView totalTv;//“歌曲总时间”
    private int totalTime;//“歌曲总时长,用于获取歌曲时长”
    private SeekBar jindutiaoSb; //"进度条"
    private boolean isStop;//“停止”
    private int position;

新建方法link()进行绑定ID:

 private void Link() {


        backIv = findViewById(R.id.listen_back_img);
        nextIv = findViewById(R.id.listen_next_img);
        discsmap = findViewById(R.id.listen_changpian_img);
        pauseIv = findViewById(R.id.listen_pause1_img);
        currentTv = findViewById(R.id.listen_current_tv);
        totalTv = findViewById(R.id.listen_length_tv);
        jindutiaoSb = findViewById(R.id.listen_jindutiao_sb);

    }

新建play()方法用于歌曲播放、唱片打碟功能,及进度条简要设置

private void play() {

        mediaPlayer.reset();//进行重置
        Bitmap disces = BitmapFactory.decodeResource(getResources(), R.mipmap.circumstance);



        }
        /////////////////////歌曲播放////////////////////////////////////////////////////
        try {
            mediaPlayer.setDataSource(music.path);
            mediaPlayer.prepare();
            mediaPlayer.start();

        } catch (IOException e) {
            e.printStackTrace();
        }

        backIv.setOnClickListener(this);
        nextIv.setOnClickListener(this);
        pauseIv.setOnClickListener(this);

        ///////////////////////////////////唱片打碟/////////////////////////////////////////////
        animator = ObjectAnimator.ofFloat(discsmap, "rotation", 0f, 360.0f);
        animator.setDuration(10000);
        animator.setInterpolator(new LinearInterpolator());//匀速
        animator.setRepeatCount(-1);//设置动画重复次数(-1代表一直转)
        animator.setRepeatMode(ValueAnimator.RESTART);//动画重复模式
        animator.start();

        ////////////////////////////////进度条/////////////////////////////////////////////////

        totalTv.setText(formatTime(music.length));//获取歌曲时长并作为文本显示
        totalTime = music.length;//获取歌曲时长
        new Thread(new SeekBarThread()).start();//线程开始
        jindutiaoSb.setMax(music.length);//设置音乐长度最大值,从而使音乐长度简单且可控


        ////////////////////////////指针拨动////////////////////////////////////////////////////
        animator1 = ObjectAnimator.ofFloat(zhizhenmap, "rotation", -60f, 0.0f);
        animator1.setDuration(900);
        animator1.setRepeatCount(0);//设置动画重复次数(-1代表一直转)
        animator1.start();

    }

获取歌曲时长并将其转化为“分:秒”形式:

 ///////////////规定需要的时间形式///////////////////////
    private String formatTime(int length) {

        Date date = new Date(length);//调用Date方法获值

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("mm:ss");//规定需要形式

        String TotalTime = simpleDateFormat.format(date);//转化为需要形式

        return TotalTime;

    }

设置事件监听:

 @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.listen_back_img://当点击“上一首”按钮
                position--;//数组递减
                if (position == -1) {
                    position = Common.musicList.size() - 1;
                }
                play();
                break;
            case R.id.listen_next_img:
                position++;
                if (position == Common.musicList.size()) {
                    position = 0;
                }
                play();
            case R.id.listen_pause1_img:

                if (mediaPlayer.isPlaying()) {
                    mediaPlayer.pause();//当正在播放时,点击“暂停”
                    animator.pause();
                    pauseIv.setImageResource(R.mipmap.start);
                } else {
                    mediaPlayer.start();//否则,播放
                    pauseIv.setImageResource(R.mipmap.icon_music_circle_pause);
                    animator.resume();
                    animator1.resume();

                }
            default:
                break;


        }
    }

建立销毁方法:

 @Override
    protected void onDestroy() {
        super.onDestroy();
        mediaPlayer.reset();
        isStop = true;
    }

运用多线程进行进度条及位置更新:

class SeekBarThread implements Runnable {

        @Override
        public void run() {
            while (mediaPlayer != null && isStop == false) {
                // 将SeekBar位置设置到当前播放位置
                handler.sendEmptyMessage(mediaPlayer.getCurrentPosition());
                try {
                    // 每100毫秒更新一次位置
                    Thread.sleep(80);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }

        }
    }

定义Handler进行接收:

 private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            jindutiaoSb.setProgress(msg.what);
            currentTv.setText(formatTime(msg.what));

        }
    };

整体代码如下:

package com.example.listviewpagerviewdemo;

public class MusicActivity extends AppCompatActivity implements View.OnClickListener {

//定义各类控件
    private ImageView backIv;
    private ImageView nextIv;
    private int position;
    private ImageView discsmap;
    private ImageView pauseIv;
    private MediaPlayer mediaPlayer;
    private ObjectAnimator animator;
    private TextView currentTv;
    private TextView totalTv;
    private int totalTime;
    private SeekBar jindutiaoSb;
    private boolean isStop;
    //接受多线程信息,安卓中不允许主线程实现UI更新
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            jindutiaoSb.setProgress(msg.what);
            currentTv.setText(formatTime(msg.what));

        }
    };


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.listen_layout);
//获取传值
        Intent intent = getIntent();
        position = intent.getIntExtra("i", 0);//将传入的值赋给position
//获取mediaplayer
        mediaPlayer = new MediaPlayer();


        Link();//绑定ID方法
        play();//歌曲播放及一系列操作方法

/////////////////////////获取进度条点击位置并使歌曲跳转到该位置////////////////////////////////////
        jindutiaoSb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                if (b) {
                    mediaPlayer.seekTo(i);
                }
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });


    }

    private void play() {

        mediaPlayer.reset();
        Music music = Common.musicList.get(position);//获取传来的值
        Bitmap disces = BitmapFactory.decodeResource(getResources(), R.mipmap.circumstance);


        /////////////////////歌曲播放////////////////////////////////////////////////////
        try {
            mediaPlayer.setDataSource(music.path);
            mediaPlayer.prepare();
            mediaPlayer.start();

        } catch (IOException e) {
            e.printStackTrace();
        }

        backIv.setOnClickListener(this);
        nextIv.setOnClickListener(this);
        pauseIv.setOnClickListener(this);

        ///////////////////////////////////唱片打碟/////////////////////////////////////////////
        animator = ObjectAnimator.ofFloat(discsmap, "rotation", 0f, 360.0f);
        animator.setDuration(10000);
        animator.setInterpolator(new LinearInterpolator());//匀速
        animator.setRepeatCount(-1);//设置动画重复次数(-1代表一直转)
        animator.setRepeatMode(ValueAnimator.RESTART);//动画重复模式
        animator.start();

        ////////////////////////////////进度条/////////////////////////////////////////////////

        totalTv.setText(formatTime(music.length));
        totalTime = music.length;
        new Thread(new SeekBarThread()).start();
        jindutiaoSb.setMax(music.length);

        ////////////////////////////指针拨动////////////////////////////////////////////////////
        animator1 = ObjectAnimator.ofFloat(zhizhenmap, "rotation", -60f, 0.0f);
        animator1.setDuration(900);
        animator1.setRepeatCount(0);//设置动画重复次数(-1代表一直转)
        animator1.start();




    }

    ///////////////获取歌曲时常///////////////////////
    private String formatTime(int length) {
        Date date = new Date(length);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("mm:ss");
        String TotalTime = simpleDateFormat.format(date);

        return TotalTime;

    }

    private void Link() {

        backIv = findViewById(R.id.listen_back_img);
        nextIv = findViewById(R.id.listen_next_img);
        discsmap = findViewById(R.id.listen_changpian_img);
        pauseIv = findViewById(R.id.listen_pause1_img);
        currentTv = findViewById(R.id.listen_current_tv);
        totalTv = findViewById(R.id.listen_length_tv);
        jindutiaoSb = findViewById(R.id.listen_jindutiao_sb);

    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.listen_back_img:
                position--;
                if (position == -1) {
                    position = Common.musicList.size() - 1;
                }
                play();
                break;
            case R.id.listen_next_img:
                position++;
                if (position == Common.musicList.size()) {
                    position = 0;
                }
                play();
            case R.id.listen_pause1_img:

                if (mediaPlayer.isPlaying()) {
                    mediaPlayer.pause();
                    animator.pause();
                    pauseIv.setImageResource(R.mipmap.start);
                } else {
                    mediaPlayer.start();
                    pauseIv.setImageResource(R.mipmap.icon_music_circle_pause);
                    animator.resume();
                    animator1.resume();

                }
            default:
                break;


        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mediaPlayer.reset();
        isStop = true;
    }

    class SeekBarThread implements Runnable {

        @Override
        public void run() {
            while (mediaPlayer != null && isStop == false) {
                // 将SeekBar位置设置到当前播放位置
                handler.sendEmptyMessage(mediaPlayer.getCurrentPosition());
                try {
                    // 每100毫秒更新一次位置
                    Thread.sleep(80);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }

        }
    }
}

Tip:

本文未将传入值进行代码讲解,仅对实现播放音乐、进度条滑动及唱片功能的实现进行了解析,需要注意的是,在除本文代码外我也单独地定义了一个工具类取名“Common”,用于存放Music类中定义的方法,在此也把代码给各位:

Common:

public class Common {
    public static List musicList = new ArrayList<>();
}

Music:

public class Music {

    public int length;//歌曲长度
    public  String  path;//歌曲获取路径

}

除去获取歌曲的时长用setMax方法外,还有更偏重“小学数学好的人”的方法,即不采用获取setMax方法,而是将歌曲长度从毫秒用类型转换及计算转化为0-100内的整数:

            float c = msg.what;
            jindutiaoSb.setProgress((int)(c/totalTime*100));

你可能感兴趣的:(android,云音乐,android,mediaplayer,音乐,relativelayout)