安卓开发音乐盒设计

音乐盒设计

1.1 环境配置

  • Android Studio 4.1.2
  • Gradle 6.5
  • JDK 12
  • Android 7.0

1.2 需求描述

1、掌握BroadCast广播机制的使用

2、使用广播进行歌曲的播放暂停、上一首、下一首功能。

1.3 演示效果

效果

二、操作步骤

2.1 设计界面

image-20210506105245470

然后准备歌曲,放置在assets文件夹下,供AssetFileDescriptor进行读取。

2.2 编写Service和Activity

Service的onCreate()中需要创建一个BroadcastReceiver创建IntentFilter,在代码里进行动态绑定。另外也可以选择在AndroidManifest.xml中进行静态绑定,但是静态绑定优先级会低于动态绑定。然后开启线程以发送广播的方式传递消息。

我们还需要添加一个监听器mPlayer.setOnCompletionListener()监听音乐是否已经播放完成,如果完成则自动切换到下一首。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
@Override
public void onCreate() {
super.onCreate();
am = getAssets();


serviceReceiver = new MyReceiver();

IntentFilter filter = new IntentFilter();
filter.addAction(MainActivity.CTL_ACTION);
registerReceiver(serviceReceiver, filter);


// 创建MediaPlayer
mPlayer = new MediaPlayer();

mPlayer.setOnCompletionListener(mp -> {
Log.d("musicService", "播放完成");
current++;
if (current >= 3) {
current = 0;
}

prepareAndPlay(musics[current]);
//发送广播通知Activity更改文本框
Intent sendIntent = new Intent(MainActivity.UPDATE_ACTION);
sendIntent.putExtra("current", current);
sendIntent.putExtra("currentTime", mPlayer.getCurrentPosition());
sendIntent.putExtra("totalTime", mPlayer.getDuration());
// 发送广播
sendBroadcast(sendIntent);

});
Intent sendIntent = new Intent(MainActivity.UPDATE_ACTION);
sendIntent.putExtra("current", current);
// 发送广播
sendBroadcast(sendIntent);

// 刷新进度条
processThread = new Thread(() -> {
while (true) {
if (status == 0x12) {
try {
Thread.sleep(1000);
Intent sendIntent1 = new Intent(MainActivity.UPDATE_ACTION);
sendIntent1.putExtra("current", current);
sendIntent1.putExtra("currentTime", mPlayer.getCurrentPosition());
sendIntent1.putExtra("totalTime", mPlayer.getDuration());
// 发送广播
sendBroadcast(sendIntent1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
processThread.start();
}

Service中还需要添加一个Receiver进行广播消息的接收处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, Intent intent) {
int control = intent.getIntExtra("control", -1);
Log.d("musicReceiver", "收到广播, control=" + 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();
if (current + 1 >= musics.length) {
current = 0;
} else {
current++;
}
prepareAndPlay(musics[current]);
status = 0x12;
break;
}
// 上一首
case 3:
if (status == 0x12 || status == 0x13) {
mPlayer.stop();
if (current - 1 < 0) {
current = musics.length - 1;
} else {
current--;
}
prepareAndPlay(musics[current]);
status = 0x12;
}

}

// 广播通知Activity更改图标、文本框
Intent sendIntent = new Intent(MainActivity.UPDATE_ACTION);
sendIntent.putExtra("update", status);
sendIntent.putExtra("current", current);
// 发送广播,将被Activity组件中的BroadcastReceiver接收到
sendBroadcast(sendIntent);
}
}

MainActivity中,我们也需要创建一个BroadcastReceiver来接收Service传递的广播并进行处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class ActivityReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// 获取Intent中的update消息,update代表播放状态
int update = intent.getIntExtra("update", -1);
// 获取Intent中的current消息,current代表当前正在播放的歌曲
int current = intent.getIntExtra("current", -1);
int totalPosition = intent.getIntExtra("totalTime", -1);
int currentPosition = intent.getIntExtra("currentTime", -1);
Log.d("activityReceiver", "收到广播");
Log.d("activityReceiver", "current:" + current + " totalPosition:" + totalPosition + " currentPosition:" + currentPosition + " update:" + update);
if (current >= 0) {
title.setText(titleStrs[current]);
author.setText(authorStrs[current]);
}

if (totalPosition >= 0) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("mm:ss", Locale.CHINA);
Date date = new Date(totalPosition);
String formatTime = simpleDateFormat.format(date);
totalTime.setText(formatTime);
}

if (currentPosition >= 0) {
double process = ((double)currentPosition / totalPosition)*100;
Log.d("activityReceiver", "当前进度:" + (double)currentPosition/totalPosition);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("mm:ss", Locale.CHINA);
Date date = new Date(currentPosition);
String formatTime = simpleDateFormat.format(date);
progressBar.setProgress((int) process);
currentTime.setText(formatTime);
}

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;
}
}
}

最后是Activity中监听点击事件,每次点击事件都会发送广播。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public void onClick(View source) {
// 创建Intent
Intent intent = new Intent("org.xr.action.CTL_ACTION");
switch (source.getId()) {
// 按下播放/暂停按钮
case R.id.play:
intent.putExtra("control", 1);
break;
case R.id.lastMusic:
intent.putExtra("control", 3);
case R.id.nextMusic:
intent.putExtra("control", 2);
}
// 发送广播,将被Service组件中的BroadcastReceiver接收到
sendBroadcast(intent);
}

核心功能到此就基本介绍完毕。

项目代码地址:https://gitee.com/retain990/musicbox