创建应用程序常量接口保存广播频道常量
在音乐播放器应用程序类里添加两个属性
– currentMusicIndex
– currentPosition
– 访问它们的方法
创建MusicPlayService来完成音乐的播放、暂停以及切换工作
利用广播来实现MainActivity与MusicPlayService之间的通信
涉及知识点
标签(TextView)
按钮(Button)
媒体播放器(MediaPlayer)
进度条(ProgressBar)
线程(Thread)
消息处理器(Handler)
列表视图(ListView)
异步任务(AsyncTask)
应用程序(Application)
服务(Service)
广播接收者(BroadcastReceiver)
创建安卓应用
将图片素材拷贝到drawable目录与mipmap目录
创建按钮背景图片选择器
在项目清单文件里授权访问外置存储卡,设置应用程序图标
主布局资源文件activity_main.xml
字符串资源文件strings.xml
创建音乐名列表项模板music_name_list_item.xml
创建ui子包,将MainActivity拖进ui子包
创建entity子包,在里面创建音乐实体类 - Music
创建app子包,在里面创建音乐播放器应用程序类 - MusicPlayerApplication
创建adapter子包,在里面创建音乐适配器 - MusicAdapter
**在app子包常见应用程序常量接口 - AppConstants
package com.example.v05.app;
/**
- 功能:应用程序常量接口
- 作者:王丹婷
- 日期:2021年01月06日
*/
interface AppConstants {
String TAG = “net.hw.sdcard_musicplayer_v05”; // 应用程序标记
String INTENT_ACTION_PREVIOUS = TAG + “.intent.action.PREVIOUS”; // 广播频道常量:播放上一首
String INTENT_ACTION_PLAY = TAG + “.intent.action.PLAY”; // 广播频道常量:播放
String INTENT_ACTION_PLAY_OR_PAUSE = TAG + “.intent.action.PLAY_OR_PAUSE”; // 广播频道常量:播放或暂停
String INTENT_ACTION_NEXT = TAG + “.intent.action.NEXT”; // 广播频道常量:播放下一首
String INTENT_ACTION_UPDATE_PROGRESS = TAG + “.intent.action.UPDATE_PROGRESS”; // 广播频道常量:更新播放进度
String CONTROL_ICON = “control_icon”; // 控制图标名称常量
String DURATION = “duration”; // 播放时长名称常量
String CURRENT_POSITION = “current_position”; // 当前播放位置名称常量
}
创建service子包,在里面创建音乐播放服务类 - MusicPlayService
创建音乐广播接收器内部类 - MusicReceiver()
主界面
package com.example.v05.ui;
import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import com.example.v05.R;
import java.util.List;
/**
-
功能:基于存储卡音乐播放器v0.5
-
王丹婷
*/
public class MainActivity extends AppCompatActivity implements AppConstants {private String musicName; // 音乐文件名
private TextView tvMusicName; // 音乐名标签
private Button btnPlayOrPause; // 播放|暂停按钮
private MusicReceiver receiver; // 音乐广播接收器
private TextView tvCurrentPosition; // 显示当前播放位置的标签
private TextView tvDuration; // 显示音乐播放时长的标签
private ProgressBar pbMusicProgress; // 音乐播放进度条
private ListView lvMusicName; // 音乐名列表控件
private List musicList; // 音乐列表(数据源)
private MusicAdapter adapter; // 音乐适配器
private MusicPlayerApplication app; // 音乐播放器应用程序对象
private ProgressBar pbScanMusic; // 扫描存储卡音乐进度条
private TextView tvScanMusic; // 扫描存储卡音乐标签(提示用户耐心等待)@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//利用布局资源文件设置用户界面
setContentView(R.layout.activity_main);// 通过资源标识符获取控件实例 lvMusicName = findViewById(R.id.lvMusicName); tvMusicName = findViewById(R.id.tvMusicName); btnPlayOrPause = findViewById(R.id.btnPlayOrPause); tvCurrentPosition = findViewById(R.id.tvCurrentPosition); tvDuration = findViewById(R.id.tvDuration); pbMusicProgress = findViewById(R.id.pbMusicProgress); pbScanMusic = findViewById(R.id.pbScanMusic); tvScanMusic = findViewById(R.id.tvScanMusic); //获取音乐播放器应用程序对象 app = (MusicPlayerApplication) getApplication(); // 定义存储读写权限数组 String[] PERMISSIONS_STORAGE = { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE }; // 检查是否有读权限 final int permission = ActivityCompat.checkSelfPermission(this, PERMISSIONS_STORAGE[0]); // 如果没有授权,那么就请求读权限 if (permission != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, PERMISSIONS_STORAGE, 0); return; } //执行填充音乐列表的异步任务 new FillMusicListTask().execute(); // 给音乐列表控件注册监听器 lvMusicName.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { // 获取音乐索引 app.setCurrentMusicIndex(position); // 当前播放位置归零 app.setCurrentPosition(0); //获取音乐名 musicName = app.getMusicList().get(position).getMusicName(); // 设置音乐名标签内容,去掉路径和扩展名 tvMusicName.setText("No." + (app.getCurrentMusicIndex() + 1) + " " + musicName.substring( musicName.lastIndexOf("/") + 1, musicName.lastIndexOf("."))); //创建意图 Intent intent = new Intent(); //设置广播频道 intent.setAction(INTENT_ACTION_PLAY); //按意图发送广播 sendBroadcast(intent); } }); //创建音乐广播接收器 receiver = new MusicReceiver(); //创建意图过滤器 IntentFilter filter = new IntentFilter(); //通过意图过滤器添加广播频道 filter.addAction(INTENT_ACTION_UPDATE_PROGRESS); //注册音乐广播接收器 registerReceiver(receiver, filter);
}
/**
-
填充音乐列表异步任务类
/
private class FillMusicListTask extends AsyncTask<Void, Integer, Void> {
/*- 耗时工作执行前
*/
@Override
protected void onPreExecute() {
super.onPreExecute();
// 显示扫描音乐进度条
pbScanMusic.setVisibility(View.VISIBLE);
// 显示扫描音乐标签
tvScanMusic.setVisibility(View.VISIBLE);
}
@Override
protected Void doInBackground(Void… voids) {
// 获取音乐列表
musicList = app.getMusicList();
// 故意耗时,要不然扫描太快结束
for (long i = 0; i < 2000000000; i++) {
}
return null;
}/**
-
耗时工作执行后
-
@param aVoid
*/
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
// 隐藏扫描音乐进度条
pbScanMusic.setVisibility(View.GONE);
// 隐藏扫描音乐标签
tvScanMusic.setVisibility(View.GONE);// 判断音乐列表是否有元素
if (musicList.size() > 0) {
// 创建音乐适配器
adapter = new MusicAdapter(MainActivity.this, musicList);
// 给音乐列表控件设置适配器
lvMusicName.setAdapter(adapter);
// 获取当前要播放的音乐名(默认是音乐播放列表的第一首)
musicName = musicList.get(0).getMusicName();
// 设置音乐名标签内容,去掉路径和扩展名,添加序号
tvMusicName.setText(“No.” + (app.getCurrentMusicIndex() + 1) + " " + musicName.substring(
musicName.lastIndexOf("/") + 1, musicName.lastIndexOf(".")));
//创建意图,用于启动音乐播放服务
Intent intent = new Intent(MainActivity.this, MusicPlayService.class);
//按意图启动服务
startService(intent);
} else {
// 提示用户没有音乐文件
Toast.makeText(MainActivity.this, “外置存储卡上没有音乐文件!”, Toast.LENGTH_SHORT);
}
}
}
- 耗时工作执行前
/**
- 音乐广播接收器
*/
private class MusicReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
//获取广播频道
String action = intent.getAction();
//判断广播频道是否为空
if (action != null) {
//根据不同广播频道执行不同操作
if (INTENT_ACTION_UPDATE_PROGRESS.equals(action)) {
//获取播放时长
int duration = intent.getIntExtra(DURATION, 0);
//获取播放控制图标
int controlIcon = intent.getIntExtra(CONTROL_ICON,
R.drawable.play_button_selector);
//计算进度值
int progress = app.getCurrentPosition() * 100 / duration;
//获取音乐名
musicName = app.getMusicList().get(app.getCurrentMusicIndex()).getMusicName();
//设置正在播放的文建明(去掉扩展名)
tvMusicName.setText(“No.” + (app.getCurrentMusicIndex() + 1) + " "
+ musicName.substring(musicName.lastIndexOf("/") + 1, musicName.lastIndexOf(".")));
//设置播放进度值标签
tvCurrentPosition.setText(app.getFormatTime(app.getCurrentPosition()));
//设置播放时长标签
tvDuration.setText(app.getFormatTime(duration));
//设置播放进度条的进度值
pbMusicProgress.setProgress(progress);
//设置【播放|暂停】按钮显示的图标
btnPlayOrPause.setBackgroundResource(controlIcon);
}
}
}
}
/**
- 上一首按钮单击事件处理方法
- @param view
*/
public void doPrevious(View view){
//创建意图
Intent intent = new Intent();
//设置广播频道
intent.setAction(INTENT_ACTION_PREVIOUS);
//按意图发送广播
sendBroadcast(intent);
}
/**
- 下一首按钮单击事件处理方法
- @param view
*/
public void doNext(View view){
//创建意图
Intent intent = new Intent();
//设置广播频道
intent.setAction(INTENT_ACTION_NEXT);
//按意图发送广播
sendBroadcast(intent);
}
/**
- 播放|暂停按钮单击事件处理方法
- @param view
*/
public void doPlayOrPause(View view) {
//创建意图
Intent intent = new Intent();
//设置广播频道
intent.setAction(INTENT_ACTION_PLAY_OR_PAUSE);
//按意图发送广播
sendBroadcast(intent);
}
/**
- 销毁回调方法,释放资源
*/
@Override
protected void onDestroy() {
super.onDestroy();
//停止音乐播放器
stopService(new Intent(MainActivity.this, MusicPlayService.class));
//注销广播接收器
unregisterReceiver(receiver);
}
private class MusicAdapter {
}private class MusicPlayerApplication {
}
} -