Android Studio音乐播放器

任务:音乐播放器

VW(5@2ZZBTGBUUOJTI4QN@P.png

主要要求:

上一首、下一首),音乐文件放在 assets/music 目录下,界面自拟。

自己完成的

4_M0RPIC(JF~S%{L42PXX@S.png

准备工作

1.使用前需要添加依赖:添加ExoPlayer依赖

W6_MDCP)L(7E3}2)E3_~EI6.png

2.新建assets目录

项目右键→New → Folder → Assets Folder

在assets目录中新建子目录: assets目录右键 → New → Directory

将音乐资源复制到assets/music下

1RJLO9I%93}N`NZQ0@M9B9P.png

E7XQKIJ0{V~OE(I46V%(]WQ.png

遇到的问题

1.用ExoPlayer媒体播放器读取assets文件里的内容,我网上搜到的全是MediaPlayer的,后来重新看了ppt,用的Uri解决。

Uri uri=Uri.parse("file:///android_asset/music/"+music_list.get(idx));
MediaItem mediaItem = MediaItem.fromUri(uri);
player.setMediaItem(mediaItem); //加载媒体资源

2.重写Activity的onDestroy()方法,用于在当前Activity销毁时,停止正在播放的音频,并释放mediaplayer所占用的资源,否则你每打开一次就会播放一次,并且上次播放的不会停止 你可以试试的,我解释不清楚。

@Override
protected void onDestroy() {
    super.onDestroy();
    player.stop();
    player.release();
}

核心代码

ActionBar:

VW(5@2ZZBTGBUUOJTI4QN@P.png
ActionBar actionBar = getSupportActionBar(); //获取ActionBar
actionBar.setTitle("Music"); //设置标题

SeekBar

VW(5@2ZZBTGBUUOJTI4QN@P.png
SeekBar.OnSeekBarChangeListener listener3 =
            new SeekBar.OnSeekBarChangeListener() {//seekBar
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress,
                                              boolean fromUser) {
                    if (prepared && fromUser) {
                        player.seekTo(progress);//从指定位置开始播放
                    }
                }
                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {
                }
                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {
                    seekBarHint1.setText(format(seekBar.getProgress()));
                }
            };
    private class ProgressUpdate extends TimerTask {//定时任务类:定时刷新SeekBar进度条
        @Override
        public void run() {
            runOnUiThread( new Runnable() {
                @Override
                public void run() {
                    long position = player.getContentPosition();//获取媒体播放的当前位置(毫秒)
//                    Log.d("flag", "pos=" + position);
                    seekBar.setProgress((int) position);//SeekBar设置进度
                    seekBarHint1.setText( format(position) );//显示当前音乐时间
                }
            });
        }
    }
    public String format(long position) {//"分:秒"格式
        SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");
        String timeStr = sdf.format(position); //会自动将时长(毫秒数)转换为分秒格式
        return timeStr;
    }

ListView

    public List<String> getMusic() {
        List<String> pList = new ArrayList<>();
        try {
            String[] fNames = getAssets().list("music"); //获取assets/music目录下所有文件名
            for (String fn : fNames) {
                pList.add(fn);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return pList;
    }

    // ListView监听器
    AdapterView.OnItemClickListener listener = new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//            ListView lv = (ListView) parent;
//            lv.setSelector(R.color.purple_200); //设置高亮背景色
            String pName = parent.getItemAtPosition(position).toString(); //获得选中项名称

            if (( pName.equals(music_list.get(idx)))&&(count!=0)) {//如果相同就音乐进度不变
                Log.d("flag","选中相同的音乐"+pName+",进度不变");
            }
            else {//如果是不同的音乐那么改变
                for(int i=0;i<music_list.size();i++){
                    if(pName.equals(music_list.get(i))){
                        Log.d("flag","选中"+pName);
                        idx=i;
                    }
                }
                initExoPlayer();
            }
        }
    };

ExoPlayer

public void initExoPlayer()  {
    //使用与file Uri使用URL几乎相同的方式来使用该方案。
    // 语法是file:///android_asset/...(请注意:三个斜杠),
    // 其中省略号是文件assets/夹中文件的路径。
    Uri uri=Uri.parse("file:///android_asset/music/"+music_list.get(idx));
    MediaItem mediaItem = MediaItem.fromUri(uri);

    count++;
    Log.d("flag","播放的第"+count+"首音乐:"+music_list.get(idx));

    music_name.setText(music_list.get(idx));
    player.setMediaItem(mediaItem); //加载媒体资源
    player.setRepeatMode(ExoPlayer.REPEAT_MODE_ONE); //单曲循环
    player.prepare(); //会触发下面的监听器↓
}


Player.Listener listener1 = new Player.Listener() {//player
    @Override
    //播放器状态监听器
    public void onPlaybackStateChanged(int playbackState) {
        if (playbackState == ExoPlayer.STATE_READY) { //播放器准备好了
            prepared = true;
            long realDurationMillis = player.getDuration();//获取媒体文件的时长(毫秒)
            seekBar.setMax((int) realDurationMillis);//设置SeekBar最大值
            seekBarHint2.setText( format(realDurationMillis) );
        }
    }
};

四个开关

View.OnClickListener listener_btn_1 = new View.OnClickListener() {//btn_1
    @Override
    public void onClick(View v) {
        if ( !prepared ) //播放器没有准备好
            return;
        if ( idx==0 ) {
            idx=music_list.size()-1;
        } else {
            idx=idx-1;
        }
        initExoPlayer();
    }
};
View.OnClickListener listener_btn_2 = new View.OnClickListener() {//btn_2
    @Override
    public void onClick(View v) {
        if ( !prepared ) //播放器没有准备好
            return;
        if ( player.isPlaying() ) {
            player.pause();
            timer.cancel(); //停止定时器
            timer = new Timer(); //新建定时器
        } else {
            player.play();
            timer = new Timer();
            timer.schedule(new ProgressUpdate(), 300, 500);
        }
    }
};
View.OnClickListener listener_btn_3 = new View.OnClickListener() {//btn_3
    @Override
    public void onClick(View v) {
        if ( !prepared ) //播放器没有准备好
            return;
        player.pause();
    }
};
View.OnClickListener listener_btn_4 = new View.OnClickListener() {//btn_4
    @Override
    public void onClick(View v) {
        if ( !prepared ) //播放器没有准备好
            return;
        if ( idx==music_list.size()-1 ) {
            idx=0;
        } else {
            idx=idx+1;
        }
        Log.d("flag"," "+idx);
        initExoPlayer();
    }
};

总代码

package com.example.mylogin;

import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;

import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.TextView;

import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.Player;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

public class MusicDomeActivity extends AppCompatActivity {

    ListView listView;
    ArrayAdapter<String>adapter;

    TextView music_name;//音乐名称
    SeekBar seekBar; //进度条
    TextView seekBarHint1; //音乐时长提示
    TextView seekBarHint2; //音乐时长提示end

    Button btn_1,btn_2,btn_3,btn_4; //播放按钮
    ExoPlayer player; //播放器
    private Timer timer; //定时器
    private boolean prepared; //播放器是否准备好
    List<String>music_list=new ArrayList<>();
    int idx=0;//正在播放的music的id
    int count=0;//第几首播放的

    public  void initView(){
        prepared = false; //初始值
        //ListView 编程
        listView = findViewById(R.id.lv_music);
        music_list = getMusic();
        adapter = new ArrayAdapter<String>(
                MusicDomeActivity.this,
                android.R.layout.simple_list_item_1,
                music_list);
        listView.setAdapter(adapter);
        listView.setOnItemClickListener(listener);
        player = new ExoPlayer.Builder(MusicDomeActivity.this).build();//创建播放器
        //开关初始化
        btn_1=findViewById(R.id.button1);
        btn_2=findViewById(R.id.button2);
        btn_3=findViewById(R.id.button3);
        btn_4=findViewById(R.id.button4);
        //进度条显示初始化
        music_name=findViewById(R.id.musictext);
        seekBar=findViewById(R.id.seekBar);
        seekBarHint1=findViewById(R.id.seekBarHint1);
        seekBarHint2=findViewById(R.id.seekBarHint2);
        //5个监听
        player.addListener(listener1);
        btn_1.setOnClickListener(listener_btn_1);
        btn_2.setOnClickListener(listener_btn_2);
        btn_3.setOnClickListener(listener_btn_3);
        btn_4.setOnClickListener(listener_btn_4);
        seekBar.setOnSeekBarChangeListener(listener3);
    }

    public List<String> getMusic() {
        List<String> pList = new ArrayList<>();
        try {
            String[] fNames = getAssets().list("music"); //获取assets/music目录下所有文件名
            for (String fn : fNames) {
                pList.add(fn);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return pList;
    }

    // ListView监听器
    AdapterView.OnItemClickListener listener = new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//            ListView lv = (ListView) parent;
//            lv.setSelector(R.color.purple_200); //设置高亮背景色
            String pName = parent.getItemAtPosition(position).toString(); //获得选中项名称

            if (( pName.equals(music_list.get(idx)))&&(count!=0)) {//如果相同就音乐进度不变
                Log.d("flag","选中相同的音乐"+pName+",进度不变");
            }
            else {//如果是不同的音乐那么改变
                for(int i=0;i<music_list.size();i++){
                    if(pName.equals(music_list.get(i))){
                        Log.d("flag","选中"+pName);
                        idx=i;
                    }
                }
                initExoPlayer();
            }
        }
    };
    public void initExoPlayer()  {
        //使用与file Uri使用URL几乎相同的方式来使用该方案。
        // 语法是file:///android_asset/...(请注意:三个斜杠),
        // 其中省略号是文件assets/夹中文件的路径。
        Uri uri=Uri.parse("file:///android_asset/music/"+music_list.get(idx));
        MediaItem mediaItem = MediaItem.fromUri(uri);

        count++;
        Log.d("flag","播放的第"+count+"首音乐:"+music_list.get(idx));

        music_name.setText(music_list.get(idx));
        player.setMediaItem(mediaItem); //加载媒体资源
        player.setRepeatMode(ExoPlayer.REPEAT_MODE_ONE); //单曲循环
        player.prepare(); //会触发下面的监听器↓
    }


    Player.Listener listener1 = new Player.Listener() {//player
        @Override
        //播放器状态监听器
        public void onPlaybackStateChanged(int playbackState) {
            if (playbackState == ExoPlayer.STATE_READY) { //播放器准备好了
                prepared = true;
                long realDurationMillis = player.getDuration();//获取媒体文件的时长(毫秒)
                seekBar.setMax((int) realDurationMillis);//设置SeekBar最大值
                seekBarHint2.setText( format(realDurationMillis) );
            }
        }
    };

    View.OnClickListener listener_btn_1 = new View.OnClickListener() {//btn_1
        @Override
        public void onClick(View v) {
            if ( !prepared ) //播放器没有准备好
                return;
            if ( idx==0 ) {
                idx=music_list.size()-1;
            } else {
                idx=idx-1;
            }
            initExoPlayer();
        }
    };
    View.OnClickListener listener_btn_2 = new View.OnClickListener() {//btn_2
        @Override
        public void onClick(View v) {
            if ( !prepared ) //播放器没有准备好
                return;
            if ( player.isPlaying() ) {
                player.pause();
                timer.cancel(); //停止定时器
                timer = new Timer(); //新建定时器
            } else {
                player.play();
                timer = new Timer();
                timer.schedule(new ProgressUpdate(), 300, 500);
            }
        }
    };
    View.OnClickListener listener_btn_3 = new View.OnClickListener() {//btn_3
        @Override
        public void onClick(View v) {
            if ( !prepared ) //播放器没有准备好
                return;
            player.pause();
        }
    };
    View.OnClickListener listener_btn_4 = new View.OnClickListener() {//btn_4
        @Override
        public void onClick(View v) {
            if ( !prepared ) //播放器没有准备好
                return;
            if ( idx==music_list.size()-1 ) {
                idx=0;
            } else {
                idx=idx+1;
            }
            Log.d("flag"," "+idx);
            initExoPlayer();
        }
    };

    SeekBar.OnSeekBarChangeListener listener3 =
            new SeekBar.OnSeekBarChangeListener() {//seekBar
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress,
                                              boolean fromUser) {
                    if (prepared && fromUser) {
                        player.seekTo(progress);//从指定位置开始播放
                    }
                }
                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {
                }
                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {
                    seekBarHint1.setText(format(seekBar.getProgress()));
                }
            };
    private class ProgressUpdate extends TimerTask {//定时任务类:定时刷新SeekBar进度条
        @Override
        public void run() {
            runOnUiThread( new Runnable() {
                @Override
                public void run() {
                    long position = player.getContentPosition();//获取媒体播放的当前位置(毫秒)
//                    Log.d("flag", "pos=" + position);
                    seekBar.setProgress((int) position);//SeekBar设置进度
                    seekBarHint1.setText( format(position) );//显示当前音乐时间
                }
            });
        }
    }
    public String format(long position) {//"分:秒"格式
        SimpleDateFormat sdf = new SimpleDateFormat("mm:ss");
        String timeStr = sdf.format(position); //会自动将时长(毫秒数)转换为分秒格式
        return timeStr;
    }

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

        ActionBar actionBar = getSupportActionBar(); //获取ActionBar
        actionBar.setTitle("Music"); //设置标题

        initView();
    }

    /*重写Activity的onDestroy()方法,用于在当前Activity销毁时,
    停止正在播放的音频,并释放mediaplayer所占用的资源,否则你每打开一次就会播放一次,
    并且上次播放的不会停止 你可以试试的,我解释不清楚*/
    @Override
    protected void onDestroy() {
        super.onDestroy();
        player.stop();
        player.release();
    }
}

activity_music_dome.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MusicDomeActivity">

    <ListView
        android:id="@+id/lv_music"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        tools:layout_editor_absoluteY="42dp" />

    <SeekBar
        android:id="@+id/seekBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="604dp"
        android:layout_marginEnd="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/seekBarHint1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="当前进度"
        android:textSize="18sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.023"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/seekBar" />

    <TextView
        android:id="@+id/seekBarHint2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="当前进度"
        android:textSize="18sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.976"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/seekBar" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="12dp"
        android:layout_marginBottom="16dp"
        android:text="上一首"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/button2" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="16dp"
        android:text="开始/暂停"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/button3" />

    <Button
        android:id="@+id/button3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="12dp"
        android:layout_marginBottom="16dp"
        android:text="停止"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/button4" />

    <Button
        android:id="@+id/button4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="16dp"
        android:text="下一首"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <TextView
        android:id="@+id/musictext"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginBottom="20dp"
        android:text="音乐名称"
        app:layout_constraintBottom_toTopOf="@+id/seekBar"
        app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
  • 14
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值