简易音乐播放器(Mediaplayer+Broadcast+Service)可拖动进度条


简易音乐播放器(Mediaplayer+Broadcast+Service)可拖动进度条

实现效果图以及功能说明

功能说明 : 支持

① 读取sdcard目录下的歌曲,列表展示

② 点击列表切换歌曲,可以切换上一首,下一首,暂停,重置音乐

③ 可以选择播放模式,按照按钮顺序分别是单曲循环,随机播放,列表循环,由于实现逻辑,需要等到当前歌曲结束才能生效

④ 可以拖拽进度条更新进度

⑤自动播放下一首,打开自动播放第一首,后台播放,重新进入状态一致

存在的问题:MainActivity活动销毁启动后台服务,但是无法做到清空后台之后暂停音乐服务(简单来说后台全部清空音乐还是继续播放)

效果图

效果动图

Video_2021-12-12_165557 00_00_20-00_00_44.gif

实现框架

实现思路

① 构建一个包装类用来保存歌曲信息、作者以及歌曲路径,作为列表的填充对象

② MainActivity 作为填充文本和图片的活动,MusicService作为更改mediaplayer的类,二者之间采用广播的形式进行数据更新

③ TextAdapter继承BaseAdapter,在原来的基础之上给每一个数据项添加监听,作为信息更改,相应的需要将对应的歌曲序号广播,传回MusicService的广播接收器,进行数据更新

④ 由于偷懒,歌曲的原始数据我在MainActivity和MusicService都获取了一次,有需要可以自己实现数据共享

⑤ 进度条以及按钮点击和列表项点击均是传回control信号给MusicService进行更新,然后MusicService传回update信号要求MainActivity更新歌曲文本

⑥ 需要开启一个线程来不断刷新进度条

实现步骤

① 进入manifest.xml 之中添加权限和服务

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<service
    android:name=".MusicService"
    android:enabled="true"
    android:exported="true" />

② 设置列表子项布局

item.xml 两个文本框分别显示歌曲名称以及作者,最后一个文本框作为分割

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="5dp"
    android:id="@+id/ll1"
    android:orientation="vertical">

    <TextView
        android:id="@+id/txt1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        />

    <TextView
        android:id="@+id/txt2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        />

    <TextView
        android:id="@+id/txt"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        />
</LinearLayout>

③ 主页面添加进度条,列表以及七个按钮 其中进度条进度点换成了一张icon

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:id="@+id/title"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:textColor="#276893"
            android:textSize="20sp" />

        <TextView
            android:id="@+id/author"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:textColor="#4a6f5d"
            android:textSize="18sp" />

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/currenPosition"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="TextView" />

        <SeekBar
            android:id="@+id/seekBar"
            android:layout_width="0dp"

            android:thumb="@drawable/pig"
            android:thumbOffset="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="6" />

        <TextView
            android:id="@+id/duration"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_weight="1"
            android:text="TextView" />

    </LinearLayout>

    <ListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="450dp" />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <ImageButton
            android:id="@+id/previous"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="@drawable/selector_btn"
            android:src="@drawable/previous_button" />
        <ImageButton
            android:id="@+id/play"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="@drawable/selector_btn"
            android:src="@drawable/play_button" />
        <ImageButton
            android:id="@+id/next"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="@drawable/selector_btn"
            android:src="@drawable/next_button" />
        <ImageButton
            android:id="@+id/stop"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:background="@drawable/selector_btn"
            android:src="@drawable/stop" />
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <ImageButton
            android:id="@+id/loop"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="@drawable/selector_btn"
            android:src="@drawable/loop" />
        <ImageButton
            android:id="@+id/random"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:background="@drawable/selector_btn"
            android:src="@drawable/random" />
        <ImageButton
            android:id="@+id/all"
            android:layout_width="0dp"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:background="@drawable/selector_btn"
            android:src="@drawable/loop_all" />

    </LinearLayout>
</LinearLayout>

④ 编写对应的方法即可

MainActivity.java

package com.example.musicdemo;

import android.Manifest;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    // 播放暂停
    public static final String CONTROL = "com.example.musicdemo.control";//控制播放、暂停
    public static final String UPDATE = "com.example.musicdemo.update";//更新界面显示

    // 定义音乐的播放状态,0x11代表没有播放;0x12代表正在播放;0x13代表暂停
    final private int NOPLAY = 0x11;
    final private int PLAYING = 0x12;
    final private int PAUSE = 0x13;
    // 记录初始的状态
    int status = NOPLAY;
    //定义UI界面上的各按钮按下时所代表的控制信号
    final private int PLAY_OR_PAUSE = 1;
    final private int STOP = 2;
    final private int NEXT = 3;
    final private int PREVIOUS = 4;
    final private int LOOP = 5;
    final private int RANDOM = 6;
    final private int LOOP_ALL = 7;
    final private int PROGRESS = 8;

    // 获取界面中显示歌曲标题、作者文本框
    TextView title, author;
    // 播放/暂停、停止按钮
    ImageButton play, stop, next, previous;
    // 广播接收类
    MainActivity.ActivityReceiver activityReceiver;

    // 显示音乐播放时长的标签
    private TextView tvDuration;
    private TextView tvCurrentPosition;
    private SeekBar sbMusicProgress;
    private ImageButton imageButton1,imageButton2,imageButton3;

    // 进度条下面的当前进度文字,将毫秒化为m:ss格式
    private SimpleDateFormat time = new SimpleDateFormat("mm:ss");

    // 歌曲列表
    private ListView AlbumList;
    //“启动”服务的intent
    Intent MusicServiceIntent;
    // 信息列表
    List<Messageinfo>info;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // 播放组件
        play = (ImageButton) this.findViewById(R.id.play);
        // 暂停组件
        stop = (ImageButton) this.findViewById(R.id.stop);
        // 下一首组件
        next = (ImageButton) this.findViewById(R.id.next);
        // 上一首组件
        previous = (ImageButton) this.findViewById(R.id.previous);
        // 总进度组件
        tvDuration = findViewById(R.id.duration);
        // 当前进度组件
        tvCurrentPosition = (TextView) findViewById(R.id.currenPosition);
        // 进度条组件
        sbMusicProgress = (SeekBar) findViewById(R.id.seekBar);
        // 歌曲名称组件
        title = (TextView) findViewById(R.id.title);
        // 歌曲作者组件
        author = (TextView) findViewById(R.id.author);
        // 单曲循环组件
        imageButton1 = (ImageButton) findViewById(R.id.loop);
        // 随机播放组件
        imageButton2 = (ImageButton) findViewById(R.id.random);
        // 列表循环组件
        imageButton3 = (ImageButton) findViewById(R.id.all);
        // 列表组件
        AlbumList = (ListView)findViewById(R.id.list);
        // 7个按钮添加监听器
        play.setOnClickListener(this);
        stop.setOnClickListener(this);
        next.setOnClickListener(this);
        previous.setOnClickListener(this);
        imageButton1.setOnClickListener(this);
        imageButton2.setOnClickListener(this);
        imageButton3.setOnClickListener(this);
        // 为MainActivity注册BroadcastReceiver 注册信息 UPDATE代表监听的信号源
        activityReceiver = new MainActivity.ActivityReceiver();
        IntentFilter filter = new IntentFilter(UPDATE);
        // 注册BroadcastReceiver
        registerReceiver(activityReceiver, filter);
        // 添加服务项
        MusicServiceIntent = new Intent(this, MusicService.class);
        // 初始化原始歌曲数据
        info = new ArrayList<Messageinfo>();
        initSongsData();
        // 添加适配器
        TextAdapter adapter = new TextAdapter(info,this);
        AlbumList.setAdapter(adapter);
        // 判断启动权限,权限不够进行申请
        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 {
            //启动服务,准备播放
            startService(MusicServiceIntent);
        }
        // 进度条添加监听
        sbMusicProgress.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
                // 查看当前进度是否变化
                if (b) {
                    // 创建 Intent
                    Intent intent = new Intent(CONTROL);
                    // 设置广播频道:用户修改播放进度
                    intent.putExtra("control", PROGRESS);
                    // 更新进度值
                    intent.putExtra("progress",i);
                    sendBroadcast(intent);
                }
            }
            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
            }
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
            }
        });
    }
    // 初始化MediaPlayer歌曲路径,让MediaPlayer进入到准备状态
    private void initSongsData() {
        // 查询数据库
        Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,null,null,null,null);
        while (cursor.moveToNext())
        {
            // 获取所有歌曲的名称、作者、以及播放路径
            String title =  cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME));
            String author =  cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
            String Data =   cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
            Messageinfo messageinfo = new Messageinfo(title,author,new File(Data));
            // 添加到封装类
            info.add(messageinfo);
        }
    }
    @Override
    public void onClick(View source) {
        // 传递给Musicservice信号,要求其改变歌曲,随之Service会传回信息要求Main这边更新图片和文本信息
        Intent intent = new Intent(CONTROL);
        switch (source.getId()) {
            // 开始播放
            case R.id.play:
                intent.putExtra("control", PLAY_OR_PAUSE);
                break;
            //  暂停播放
            case R.id.stop:
                intent.putExtra("control", STOP);
                break;
            //  下一首
            case R.id.next:
                intent.putExtra("control",NEXT);
                break;
            //  上一首
            case R.id.previous:
                intent.putExtra("control",PREVIOUS);
                break;
            //  单曲循环
            case R.id.loop:
                intent.putExtra("control",LOOP);
                break;
            //  随机播放
            case R.id.random:
                intent.putExtra("control",RANDOM);
                break;
            //  顺序循环
            case R.id.all:
                intent.putExtra("control",LOOP_ALL);
                break;
        }
        // 发送广播 ,将被Service组件中的BroadcastReceiver接收到
        sendBroadcast(intent);
    }

    // 自定义的BroadcastReceiver,负责进行进度条等文本信息以及图片信息的更新
        public class ActivityReceiver extends BroadcastReceiver {
        public void onReceive(Context context, Intent intent) {
            // 获取Intent中的update消息,update代表播放状态,默认为-1
            int update = intent.getIntExtra("update", -1);
            // 当前时长
            int current_position = intent.getIntExtra("current_position", -1);
            // 总时长
            int duration = intent.getIntExtra("songs_duration", -1);
            if(current_position != -1)// 说明此时只需要更新进度条
            {
                tvCurrentPosition.setText(time.format(current_position));
                // 设置播放拖拽条的进度值,进度值的百分比 current_position当前进度 duration 总时长
                sbMusicProgress.setProgress(current_position* 100/duration );
            }
            else // 需要更新其它信息
            {
                // 文本框更新标题以及作者
                String songs_title = intent.getStringExtra("songs_title");
                String songs_author = intent.getStringExtra("songs_author");
                title.setText(songs_title);
                author.setText(songs_author);
                // 更新当前播放时长 转化为mm:ss的格式
                tvDuration.setText(time.format(duration));
                switch (update) {
                    // 未播放状态
                    case NOPLAY:
                        // 未播放状态下设置使用播放图标
                        play.setImageResource(R.drawable.play);
                        // 设置当前状态
                        status = NOPLAY;
                        // 播放时长重置
                        tvCurrentPosition.setText("00:00");
                        // 进度清零
                        sbMusicProgress.setProgress(0);
                        break;
                    // 进入播放状态
                    case PLAYING:
                        // 播放状态下设置使用暂停图标
                        play.setImageResource(R.drawable.pause);
                        // 设置当前状态
                        status = PLAYING;
                        break;
                    // 控制播放器进入暂停状态
                    case PAUSE:
                        // 暂停状态下设置使用播放图标
                        play.setImageResource(R.drawable.play);
                        // 设置当前状态
                        status = PAUSE;
                        break;
                }
            }
        }
    }
    //获取到权限回调方法
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        switch (requestCode) {
            case 1:
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    startService(MusicServiceIntent);
                } else {
                    Toast.makeText(this, "权限不够获取不到音乐,程序将退出", Toast.LENGTH_SHORT).show();
                    finish();
                }
                break;
            default:
                break;
        }
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 解除注册
        unregisterReceiver(activityReceiver);
        // 切换到服务项,后台进行运行
        MusicServiceIntent = new Intent(this, MusicService.class);
    }
}

TextAdapter.java

package com.example.musicdemo;

import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.os.RemoteException;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.HashMap;
import java.util.List;
import java.util.zip.Inflater;

public class TextAdapter extends BaseAdapter {
    public static final String CONTROL = "com.example.musicdemo.control";//控制播放、暂停
    // 歌曲列表
    public List<Messageinfo>list;
    // 获取Main界面的布局 以及context
    private LayoutInflater mInflater;
    private Context context;
    // 更新歌曲
    final private int NOW = 9;
    public TextAdapter(List<Messageinfo>list, Context context)
    {
        super();
        // 接收数据
        this.list = list;
        // 获取Main界面的布局 以及context
        mInflater = LayoutInflater.from(context);
        this.context = context;
    }
    @Override
    public int getCount() {
        return list.size();
    }

    @Override
    public Object getItem(int i) {
        return list.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {
        // 复用,降低时间复杂度
        ViewHolder holder = null;
        if(view == null) {
            view = mInflater.inflate(R.layout.item, viewGroup,false);
            //   可以被重用的视图   两个参数  第一个参数就是   分布的资源id   第二个就是填充的根视图
            holder = new ViewHolder();
            // 两个文本框 标题以及作者
            holder.txt1 = (TextView) view.findViewById(R.id.txt1);
            holder.txt2 = (TextView) view.findViewById(R.id.txt2);
            // 布局
            holder.ll1 = (LinearLayout) view.findViewById(R.id.ll1);
            view.setTag(holder);
        }
        else
            holder = (ViewHolder) view.getTag();
        Messageinfo mess = list.get(i);
        /// 填充数据
        holder.txt1.setText("歌曲:" + mess.getTitle());
        holder.txt2.setText( "歌手:" + mess.getAuthor());
        // 添加监听
        holder.ll1.setOnClickListener( new ClickListener(i));
        return view;
    }
    class ClickListener implements Button.OnClickListener{
        // 标记位确定是哪一个列表项
        private  int position;
        public ClickListener(int i)
        {
            this.position = i;
        }
        @Override
        public void onClick(View v){
            // 创建 Intent
            Intent intent = new Intent(CONTROL);
            // 设置广播频道:用户修改播放歌曲
            intent.putExtra("control", NOW);
            // 传回播放歌曲序号
            intent.putExtra("now",position);
            // 按意图发送广播
            context.sendBroadcast(intent);
        }
    };
    /// 复用类
    public final class ViewHolder{
        public TextView txt1;
        public TextView txt2;
        LinearLayout ll1;
    }
}

MusicService.java

package com.example.musicdemo;


import android.app.Activity;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.media.MediaPlayer;
import android.os.Environment;
import android.os.IBinder;
import android.provider.MediaStore;
import android.util.Log;
import android.view.LayoutInflater;
import android.widget.Adapter;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SeekBar;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MusicService extends Service  {

    // 当前的状态,0x11 代表没有播放 0x12代表 正在播放 0x13 代表暂停
    final private int NOPLAY = 0x11;
    final private int PLAYING = 0x12;
    final private int PAUSE = 0x13;
    // 状态标记位
    private int status = NOPLAY;

    //定义UI界面上的各按钮按下时所代表的控制信号
    final private int PLAY_OR_PAUSE = 1;
    final private int STOP = 2;
    final private int NEXT = 3;
    final private int PREVIOUS = 4;
    final private int LOOP = 5;
    final private int RANDOM = 6;
    final private int LOOP_ALL = 7;
    final private int PROGRESS = 8;
    final private int NOW = 9;

    // 当前歌曲总时长
    private int currentDuration = 0;
    // 循环形式标记位 0代表列表循环 1代表单曲循环 2代表随机播放
    private int loop_type = 0;
    // 歌曲总数
    private int songsCount = 0;
    // 记录当前正在播放的音乐
    private int current = 0;
    // 进度条下面的当前进度文字,将毫秒化为m:ss格式
    private SimpleDateFormat time = new SimpleDateFormat("mm:ss");
    // 广播接收器
    private ServiceReceiver serviceReceiver;
    // 音乐播放器组件
    private MediaPlayer mPlayer;
    // 线程运行状态标记位 true表示正在运行
    private boolean isRunning;
    // 播放的音乐列表
    List<Messageinfo>info;
    // 线程
    Thread thread;

    public MusicService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        throw new UnsupportedOperationException("Not yet implemented");
    }

    public void onCreate(){
        // 创建BroadcastReceiver
        serviceReceiver = new ServiceReceiver();
        // 初始化数据
        info  = new ArrayList<Messageinfo>();
        initSongsData();
        songsCount = info.size();
        // 创建IntentFilter,MainActivity.CONTROL代表接收信息来源
        IntentFilter filter = new IntentFilter(MainActivity.CONTROL);
        // 注册广播接收器
        registerReceiver(serviceReceiver, filter);
        // 创建MediaPlayer
        mPlayer = new MediaPlayer();
        // 播放当前第一首歌曲
        Intent sendIntent = new Intent(MainActivity.UPDATE);
        // 获取第一首歌曲信息
        Messageinfo messageinfo = info.get(current);
        // 按照路径准备歌曲
        prepareAndPlay((File)messageinfo.getPath());
        // 更新状态
        status = PLAYING;
        // 广播更新信息
        sendIntent.putExtra("update", status);
        sendIntent.putExtra("songs_title",(String)messageinfo .getTitle());
        sendIntent.putExtra("songs_author",(String)messageinfo.getAuthor());
        // 发送广播 ,将被MainActivity组件中的BroadcastReceiver接收到
        sendIntent.putExtra("songs_duration", mPlayer.getDuration());
        sendBroadcast(sendIntent);

        // 为MediaPlayer播放完成事件绑定监听器
        mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener(){
            public void onCompletion(MediaPlayer mp){
                // 完成播放查看当前的循环标记位
                /*
                    列表循环直接下一首
                    单曲循环则歌曲标记current不需要做更新操作,下一次直接继续播放之前的音乐
                    随机播放直接在[0,info.size()-1]范围内随机数
                 */
                if (loop_type==0) setNextMusic();
                else if (loop_type==1);
                else if (loop_type==2)
                {
                    int max=info.size()-1,min=0;
                    long randomNum = System.currentTimeMillis();
                    current = (int) (randomNum%(max-min)+min);
                }
                /* 发送广播通知Activity更改文本框 */
                Intent sendIntent = new Intent(MainActivity.UPDATE);
                Messageinfo messageinfo = info.get(current);
                prepareAndPlay((File)messageinfo.getPath());
                status = PLAYING;
                sendIntent.putExtra("update", status);
                sendIntent.putExtra("songs_title",(String)messageinfo .getTitle());
                sendIntent.putExtra("songs_author",(String)messageinfo.getAuthor());
                // 发送广播 ,将被Activity组件中的BroadcastReceiver接收到
                sendIntent.putExtra("songs_duration", mPlayer.getDuration());
                sendBroadcast(sendIntent);
                // 准备、并播放音乐
            }
        });
        super.onCreate();
        // 设置线程循环控制变量为真
        isRunning = true;
        // 创建线程更新播放进度
        // 判断音乐是否在播放
        // 创建意图 :更新播放进度
        // 让意图携带当前播放时点
        // 按意图发送广播
        // 让线程睡眠500毫秒
        thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (isRunning) {
                    // 判断音乐是否在播放
                    if (mPlayer.isPlaying()) {
                        // 创建意图 :更新播放进度
                        Intent sendIntent = new Intent(MainActivity.UPDATE);
                        sendIntent.putExtra("update", status);
                        // 让意图携带当前播放时点
                        sendIntent.putExtra("current_position", mPlayer.getCurrentPosition());
                        sendIntent.putExtra("songs_duration",mPlayer.getDuration());
                        // 按意图发送广播
                        sendBroadcast(sendIntent);
                    }
                    // 让线程睡眠500毫秒
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        // 启动线程
        thread.start();
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 后台重启时更新页面,恢复到退出之前的状态
        Intent sendIntent = new Intent(MainActivity.UPDATE);
        Messageinfo messageinfo = info.get(current);
        status = PLAYING;
        sendIntent.putExtra("update", status);
        sendIntent.putExtra("songs_title", (String) messageinfo.getTitle());
        sendIntent.putExtra("songs_author", (String) messageinfo.getAuthor());
        sendIntent.putExtra("songs_duration",mPlayer.getDuration());
        // 按意图发送广播
        sendBroadcast(sendIntent);
        return super.onStartCommand(intent, flags, startId);
    }
    // 下一首更新标记即可,溢出清零
    private void setNextMusic()
    {
        current++;
        if (current >= songsCount){
            current = 0;
        }
    }
    // 上一首更新标记即可,越界设置最后一首
    private void setPrieviousMusic()
    {
        current--;
        if (current <0){
            current = songsCount-1;
        }
    }
    // 初始化MediaPlayer歌曲路径,让MediaPlayer进入到准备状态
    private void initSongsData() {
        // 查询数据库
        Cursor cursor = getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,null,null,null,null);
        while (cursor.moveToNext())
        {
            // 获取所有歌曲的名称、作者、以及播放路径
            String title =  cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME));
            String author =  cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.ARTIST));
            String Data =   cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
            Messageinfo messageinfo = new Messageinfo(title,author,new File(Data));
            // 添加到封装类
            info.add(messageinfo);
        }
    }

    public class ServiceReceiver extends BroadcastReceiver {
        public void onReceive(final Context context, Intent intent){
            // 更新音乐 control代表更新播放音乐,update代表更新图片以及音乐信息
            int control = intent.getIntExtra("control", -1);
            // 获取当前音乐
            Messageinfo messageinfo = info.get(current);
            // 标记当前是更新循环格式还是更新状态 false代表循环格式
            boolean flag = true;
            switch (control){
                // 播放或暂停
                case PLAY_OR_PAUSE:
                    // 原来处于没有播放状态
                    if (status == NOPLAY){
                        // 准备、并播放音乐
                        prepareAndPlay((File)messageinfo.getPath());
                        // 更新状态
                        status = PLAYING;
                    }
                    // 原来处于播放状态
                    else if (status == PLAYING){
                        // 暂停
                        mPlayer.pause();
                        // 改变为暂停状态
                        status = PAUSE;
                    }
                    // 原来处于暂停状态
                    else if (status == PAUSE){
                        // 播放
                        mPlayer.start();
                        // 改变状态
                        status = PLAYING;
                    }
                    break;
                // 停止声音
                case STOP:
                    // 如果原来正在播放或暂停
                    if (status == PLAYING || status == PAUSE){
                        // 标记位清零
                        current = 0;
                        // 重置歌曲
                        mPlayer.reset();
                        // 状态更改为未播放
                        status = NOPLAY;
                    }
                    break;
                // 下一首
                case NEXT:
                    // 更新 current
                    setNextMusic();
                    // 更新状态
                    status = PLAYING;
                    // 获取下一首歌曲的信息
                    messageinfo = info.get(current);
                    // 准备播放下一首
                    prepareAndPlay((File)messageinfo.getPath());
                    break;
                // 上一首
                case PREVIOUS:
                    // 更新 current
                    setPrieviousMusic();
                    // 更新状态
                    status = PLAYING;
                    // 获取上一首歌曲的信息
                    messageinfo = info.get(current);
                    // 准备播放上一首
                    prepareAndPlay((File)messageinfo.getPath());
                    break;
                // 进度条被拖拽
                case  PROGRESS:
                    // 状态转化为播放
                    status = PLAYING;
                    // 获取进度百分比 (整数)
                    int progress = intent.getIntExtra("progress", -1);
                    mPlayer.seekTo(progress*currentDuration/100);
                    break;
                // 列表项被点击切换歌曲
                case NOW:
                    // 状态转化为播放
                    status = PLAYING;
                    // 获取被点击歌曲的序号
                    int x= intent.getIntExtra("now", 0);
                    // 更新歌曲
                    prepareAndPlay((File)info.get(x).getPath());
                    messageinfo = info.get(x);
                    // 更新current
                    current = x;
                    break;
                // 列表循环
                case LOOP_ALL:
                    flag = false;
                    loop_type = 0;
                    break;
                // 单曲循环
                case LOOP:
                    flag = false;
                    loop_type = 1;
                    break;
                // 随机播放
                case RANDOM:
                    flag = false;
                    loop_type = 2;
                    break;
            }
            // 当前是更新信息并非更新循环样式,循环样式要等到歌曲结束才更新信息
            if (flag) {
                /* 发送广播通知Activity更改图标、文本框 */
                Intent sendIntent = new Intent(MainActivity.UPDATE);
                sendIntent.putExtra("update", status);
                sendIntent.putExtra("songs_title", (String) messageinfo.getTitle());
                sendIntent.putExtra("songs_author", (String) messageinfo.getAuthor());
                if (status == NOPLAY) {
                    sendIntent.putExtra("songs_title", "");
                    sendIntent.putExtra("songs_author", "");
                }
                if (status == PLAYING || status == PAUSE)
                    sendIntent.putExtra("songs_duration", mPlayer.getDuration());
                // 发送广播 ,将被Activity组件中的BroadcastReceiver接收到
                sendBroadcast(sendIntent);
            }
        }
    }


    private void prepareAndPlay(File songsPath){
        try{
            mPlayer.reset();
            // 使用MediaPlayer加载指定的声音文件。
            mPlayer.setDataSource(songsPath.getPath());
            // 准备声音
            mPlayer.prepare();
            // 获取总时长
            currentDuration = mPlayer.getDuration();
            // 播放
            mPlayer.start();
        }
        catch (IOException e){
            e.printStackTrace();
        }
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        // 解除注册
        unregisterReceiver(serviceReceiver);
        // 释放媒体播放器
        if (mPlayer != null) {
            mPlayer.stop();
            mPlayer.release();
            mPlayer = null;
        }
        // 设置线程循环控制变量
        isRunning = false;
        // 销毁子线程
        thread = null;
    }
}

Messageinfo.java

package com.example.musicdemo;


import java.io.File;

public class Messageinfo {
    // 歌曲标题
    private String title;
    // 歌曲作者
    private String author;
    // 歌曲路径
    private File path;
    //构造方法
    public Messageinfo(String title,String author,File path) {
         this.title = title;
         this.author = author;
         this.path = path;
    }
    public String getTitle()
    {
        return title;
    }
    public  String getAuthor()
    {
        return author;
    }
    public File getPath()
    {
        return path;
    }
}


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM