简易音乐播放器

项目概述

  • Android Studio 4.1.3
  • Gradle 6.5
  • JDK 8
  • Android 11.0

基本功能:播放和暂停音乐,停止音乐,切换到上一首或者下一首音乐
进阶功能:显示歌曲信息、循环播放和进度条同步


一、布局设计

整体采用线性布局模式,从上至下依次为

  • 歌曲信息展示界面
  • 歌曲进度显示界面
  • 操作按钮界面
    main.xml

二、编写MusicService

  1. 实现音乐播放的功能(通过MediaPlayer)
  2. 能够接受广播,根据广播内容来控制播放状态

1.播放音乐

将代码进行封装,达到复用的目的

private void prepareAndPlay(String music)
	{
		try
		{
			// 打开指定音乐文件
			AssetFileDescriptor afd = am.openFd(music);
			mPlayer.reset();
			// 使用MediaPlayer加载指定的声音文件。
			mPlayer.setDataSource(afd.getFileDescriptor(),
					afd.getStartOffset(), afd.getLength());
			// 准备声音
			mPlayer.prepare();
			// 播放
			mPlayer.start();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}

2.循环播放

实现MediaPlayer的Completion监听器,监测歌曲播放状态,当歌曲播放结束时自动切换到下一首歌曲

		// 创建MediaPlayer
		mPlayer = new MediaPlayer();
		// 为MediaPlayer播放完成事件绑定监听器
		mPlayer.setOnCompletionListener(mp -> {
			Log.d("MusicService", "歌曲播放完毕");
			current++;
			if (current >= 3)
			{
				current = 0;
			}
			//发送广播通知Activity更改文本框
			Intent sendIntent = new Intent(MainActivity.UPDATE_ACTION);
			sendIntent.putExtra("current", current);
			// 发送广播,将被Activity组件中的BroadcastReceiver接收到
			sendBroadcast(sendIntent);
			// 准备并播放音乐
			prepareAndPlay(musics[current]);
		});

3.广播通信

动态注册接收器广播

		@Override
		public void onCreate()
		{
			//其他部分代码
			
			// 创建BroadcastReceiver
			serviceReceiver = new MyReceiver();
			// 创建IntentFilter
			IntentFilter filter = new IntentFilter();
			filter.addAction(MainActivity.CTL_ACTION);
			registerReceiver(serviceReceiver, filter);

			//其余部分代码
		}

整体逻辑比较简单,通过广播中control的值来进行switch case控制。

public class MyReceiver extends BroadcastReceiver
	{
		@Override
		public void onReceive(final Context context, Intent intent)
		{
			// 获取Intent中的Control状态
			int control = intent.getIntExtra("control", -1);
			Log.d("MyReceiver", "MusicService has received a broadcast and the control is "+control);
			switch (control)
			{
				// 播放或暂停
				case 1:
					// 原来处于没有播放状态
					if (status == 0x11)
					{
						// 准备并播放音乐
						prepareAndPlay(musics[current]);
						status = 0x12;
					}
					// 原来处于播放状态
					else if (status == 0x12)
					{
						// 暂停
						mPlayer.pause();
						// 改变为暂停状态
						status = 0x13;
					}
					// 原来处于暂停状态
					else if (status == 0x13)
					{
						// 播放
						mPlayer.start();
						// 改变状态
						status = 0x12;
					}
					break;
				//停止声音
				case 2:
					if (status == 0x12 || status == 0x13) {
						mPlayer.stop();
						status = 0x11;
					}
					break;
			}
			// 广播通知Activity更改图标、文本框
			Intent sendIntent = new Intent(MainActivity.UPDATE_ACTION);
			sendIntent.putExtra("update", status);
			sendIntent.putExtra("current", current);
			// 发送广播,将被Activity组件中的BroadcastReceiver接收到
			sendBroadcast(sendIntent);
		}
	}

4.进度条

采用线程方式实现,监测歌曲播放状态,然后给主线程发送广播通知其修改相关进度条显示,设置线程休眠时长,避免过于频繁地刷新界面造成程序卡顿

@Override
	public void onCreate()
	{
		//其余部分代码
		
		// 刷新进度条
		processThread = new Thread(() -> {
			while (true) {
				// 如果是播放状态
				if (status == 0x12) {
					try {
						// 休眠一秒
						Thread.sleep(1000);
						// 给主线程发送广播
						Intent sendIntent1 = new Intent(MainActivity.UPDATE_ACTION);
						// 当前进度
						sendIntent1.putExtra("currentTime", mPlayer.getCurrentPosition());
						// 总进度
						sendIntent1.putExtra("totalTime", mPlayer.getDuration());
						// 发送广播,将被Activity组件中的BroadcastReceiver接收到
						sendBroadcast(sendIntent1);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		});
		processThread.start();
	}

三、编写MainActivity

定义两个行为分别用于MainActivity和MusicService监听的动作

static final String CTL_ACTION = "org.zzw.action.CTL_ACTION";
static final String UPDATE_ACTION = "org.zzw.action.UPDATE_ACTION";

动态注册Receiver

@Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        // 创建IntentFilter
        IntentFilter filter = new IntentFilter();
        // 指定BroadcastReceiver监听的Action
        filter.addAction(UPDATE_ACTION);
        // 注册BroadcastReceiver
        registerReceiver(activityReceiver, filter);

        // 启动后台Service
        startService(new Intent(this, MusicService.class));
    }

自定义广播接收器,负责监听Service回传的广播

// 自定义的BroadcastReceiver,负责监听从Service传回来的广播
    public class ActivityReceiver extends BroadcastReceiver
    {
        @Override
        public void onReceive(Context context, Intent intent)
        {
            // 获取Intent中携带的各种信息

            //设置歌曲信息
            //设置歌曲时长
            //设置进度条和当前进度
           
           //根据update值进行选择控制
            switch (update)
            {
                case 0x11:
                    play.setImageResource(R.drawable.play);
                    status = 0x11;
                    break;
                // 控制系统进入播放状态
                case 0x12:
                    // 播放状态下设置使用暂停图标
                    play.setImageResource(R.drawable.pause);
                    // 设置当前状态
                    status = 0x12;
                    break;
                // 控制系统进入暂停状态
                case 0x13:
                    // 暂停状态下设置使用播放图标
                    play.setImageResource(R.drawable.play);
                    // 设置当前状态
                    status = 0x13;
                    break;
            }
        }
    }

四、演示效果

在这里插入图片描述


点击此处查看项目完整代码

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值