效果图

在这里插入图片描述

编写布局文件

<TextView
    android:id="@+id/music_name"
    android:layout_gravity="left"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:text="未获取"
    android:textSize="30sp"
    />

<SeekBar
    android:id="@+id/playSeekBar"
    android:layout_width="395dp"
    android:layout_height="wrap_content"/>

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    >

    <Button
        android:layout_marginLeft="10dp"
        android:id="@+id/play"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:text="播放"/>

    <TextView
        android:id="@+id/music_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="未获取"
        />

    <Button
        android:layout_marginRight="10dp"
        android:id="@+id/stop"
        android:layout_alignParentRight="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="不单曲循环"/>

</RelativeLayout>

逻辑部分

private MediaPlayer mediaPlayer=new MediaPlayer();
    private Button paly;
    private Button stop;
    private SeekBar seekBar;
    private Timer timer;
    private TextView musictime;
    private TextView musicname;
    private File file;
    private int musictimes=0;
    private int musictimes_f=0;
    private int musictimes_s=0;

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

        paly=findViewById(id.play);
        stop=findViewById(id.stop);
        musictime=findViewById(id.music_time);
        musicname=findViewById(id.music_name);
        seekBar = (SeekBar) findViewById(id.playSeekBar);

        paly.setOnClickListener(this);
        stop.setOnClickListener(this);


        permisson();

        bindViews();


    }

首先定义了变量在oncreate中获取了空间并调用了申请权限的permisson();函数与控制音乐进度条的bindViews();

申请权限

 public void permisson(){
        if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
        }else{
            initMediaPlay();
        }
    }

执行完这个函数会自动调用onRequestPermissionsResult函数

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode){
        case 1:
            if (grantResults.length>0 && grantResults[0]==PackageManager.PERMISSION_GRANTED){
                initMediaPlay();
            }else {
                Toast.makeText(this,"请打开访问存储空间的权限",Toast.LENGTH_SHORT).show();
            }

            break;

        default:
            break;
    }
}

缓冲音乐

在获得权限之后会缓冲音乐调用initMediaPlay();

 private void initMediaPlay(){
       /* Environment.getExternalStorageDirectory()获取根路径的方式不友好,比如app删除,app对应的图片不删除,
       保存路径是sd卡根路径
                替代方案
        getExternalFilesDir(Environment.DIRECTORY_PICTURES) 注意:前面没有Environment,app删除对应的图片相应删除,
        保护隐私,保存路径是/storage/emulated/0/Android/data/com.wintec.huashang/files/Pictures*/
        /*File file=new File(Environment.getExternalStorageDirectory(),"");*/

       /* getExternalCacheDir()方法可以将文件放在SD卡的应用关联缓存目录*/

        /*file的用法参考https://blog.csdn.net/lj317499/article/details/112778167*/

        try {
            file=new File(getExternalCacheDir(),"music.mp3");
            mediaPlayer.setDataSource(file.getPath());

            mediaPlayer.prepare();
            seekBar.setMax(mediaPlayer.getDuration());
            musicname.setText(file.getName());

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


    }

这里先将准备好播放的文件放在了应用的SD卡的应用关联缓存目录通过file类获取了文件,再通过mediaPlayer设置了进度条与音乐名称

设置按钮的点击事件

public void onClick(View view) {
    switch (view.getId()){
        case id.play:
            permisson();
            if ( paly.getText().equals("播放")){
                mediaPlayer.start();
                paly.setText("暂停");
                timer();
            }else if(paly.getText().equals("暂停")) {
                mediaPlayer.pause();
                paly.setText("播放");
                timer.cancel();
            }
            break;
        case id.stop:
            if (stop.getText().equals("单曲循环")){
                stop.setText("不单曲循环");

            }else {
                stop.setText("单曲循环");
            }
            break;

        default:
            break;


    }
}

这里通过点击按钮切换播放器的播放模式和音乐的播放与暂停并控制启停timer。

 public void timer(){
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {

                    seekBar.setProgress(mediaPlayer.getCurrentPosition());
                    musictimes=seekBar.getMax()-seekBar.getProgress();
                    musictimes_f=musictimes/60000;
                    musictimes_s=(musictimes%60000)/1000;
                    musictime.post(new Runnable() {
                        @Override
                        public void run() {
                            musictime.setText(musictimes_f+":"+musictimes_s);
                        }
                    });

                if (seekBar.getMax()==seekBar.getProgress() && stop.getText().equals("单曲循环")){
                    mediaPlayer.seekTo(0);
                    mediaPlayer.start();
                }
                if (seekBar.getMax()==seekBar.getProgress() && stop.getText().equals("不单曲循环")){
                    musictime.post(new Runnable() {
                        @Override
                        public void run() {
                            mediaPlayer.seekTo(0);
                            seekBar.setProgress(0);
                            onClick(paly);
                            timer.cancel();
                        }
                    });
                }

            /*    Log.d(String.valueOf(MainActivity.this),"时间长度"+musictimes_s);*/
            }

        },0,100);
    }

timer中控制着进度条的刷新和音乐剩余时间的刷新以及音乐播放完后控制音乐的再次播放和暂停。

  private void bindViews() {
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if(fromUser==true){
                    mediaPlayer.seekTo(progress);
                }
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                if (mediaPlayer.isPlaying()){
                    mediaPlayer.pause();
                }

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                permisson();
                mediaPlayer.seekTo(seekBar.getProgress());
                mediaPlayer.start();
                if (paly.getText().equals("播放")){
                    onClick(paly);
                }
            }
        });
    }

这个函数控制进度条的功能。

最后退出的时候清空timer和 mediaPlayer

 @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mediaPlayer!=null){
            mediaPlayer.stop();
            mediaPlayer.release();
            timer.cancel();
            timer = null;
        }
    }

到这里一个简单的音乐播放器就制作完成了

所有代码

package com.example.playaudiotest;

import static com.example.playaudiotest.R.*;
import static com.example.playaudiotest.R.color.*;

import androidx.annotation.ColorLong;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;

import android.Manifest;
import android.content.pm.PackageManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{

    private MediaPlayer mediaPlayer=new MediaPlayer();
    private Button paly;
    private Button stop;
    private SeekBar seekBar;
    private Timer timer;
    private TextView musictime;
    private TextView musicname;
    private File file;
    private int musictimes=0;
    private int musictimes_f=0;
    private int musictimes_s=0;

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

        paly=findViewById(id.play);
        stop=findViewById(id.stop);
        musictime=findViewById(id.music_time);
        musicname=findViewById(id.music_name);
        seekBar = (SeekBar) findViewById(id.playSeekBar);

        paly.setOnClickListener(this);
        stop.setOnClickListener(this);


        permisson();

        bindViews();


    }

    private void initMediaPlay(){
       /* Environment.getExternalStorageDirectory()获取根路径的方式不友好,比如app删除,app对应的图片不删除,
       保存路径是sd卡根路径
                替代方案
        getExternalFilesDir(Environment.DIRECTORY_PICTURES) 注意:前面没有Environment,app删除对应的图片相应删除,
        保护隐私,保存路径是/storage/emulated/0/Android/data/com.wintec.huashang/files/Pictures*/
        /*File file=new File(Environment.getExternalStorageDirectory(),"");*/

       /* getExternalCacheDir()方法可以将文件放在SD卡的应用关联缓存目录*/

        /*file的用法参考https://blog.csdn.net/lj317499/article/details/112778167*/

        try {
            file=new File(getExternalCacheDir(),"music.mp3");
            mediaPlayer.setDataSource(file.getPath());

            mediaPlayer.prepare();
            seekBar.setMax(mediaPlayer.getDuration());
            musicname.setText(file.getName());

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


    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case id.play:
                permisson();
                if ( paly.getText().equals("播放")){
                    mediaPlayer.start();
                    paly.setText("暂停");
                    timer();
                }else if(paly.getText().equals("暂停")) {
                    mediaPlayer.pause();
                    paly.setText("播放");
                    timer.cancel();
                }
                break;
            case id.stop:
                if (stop.getText().equals("单曲循环")){
                    stop.setText("不单曲循环");

                }else {
                    stop.setText("单曲循环");
                }
                break;

            default:
                break;


        }
    }



    public void timer(){
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {

                    seekBar.setProgress(mediaPlayer.getCurrentPosition());
                    musictimes=seekBar.getMax()-seekBar.getProgress();
                    musictimes_f=musictimes/60000;
                    musictimes_s=(musictimes%60000)/1000;
                    musictime.post(new Runnable() {
                        @Override
                        public void run() {
                            musictime.setText(musictimes_f+":"+musictimes_s);
                        }
                    });

                if (seekBar.getMax()==seekBar.getProgress() && stop.getText().equals("单曲循环")){
                    mediaPlayer.seekTo(0);
                    mediaPlayer.start();
                }
                if (seekBar.getMax()==seekBar.getProgress() && stop.getText().equals("不单曲循环")){
                    musictime.post(new Runnable() {
                        @Override
                        public void run() {
                            mediaPlayer.seekTo(0);
                            seekBar.setProgress(0);
                            onClick(paly);
                            timer.cancel();
                        }
                    });
                }

            /*    Log.d(String.valueOf(MainActivity.this),"时间长度"+musictimes_s);*/
            }

        },0,100);
    }

    private void bindViews() {
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if(fromUser==true){
                    mediaPlayer.seekTo(progress);
                }
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                if (mediaPlayer.isPlaying()){
                    mediaPlayer.pause();
                }

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                permisson();
                mediaPlayer.seekTo(seekBar.getProgress());
                mediaPlayer.start();
                if (paly.getText().equals("播放")){
                    onClick(paly);
                }
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mediaPlayer!=null){
            mediaPlayer.stop();
            mediaPlayer.release();
            timer.cancel();
            timer = null;
        }
    }

    public void permisson(){
        if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(MainActivity.this,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
        }else{
            initMediaPlay();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        switch (requestCode){
            case 1:
                if (grantResults.length>0 && grantResults[0]==PackageManager.PERMISSION_GRANTED){
                    initMediaPlay();
                }else {
                    Toast.makeText(this,"请打开访问存储空间的权限",Toast.LENGTH_SHORT).show();
                }

                break;

            default:
                break;
        }
    }


}
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐