开发一个简易音乐播放器,要求实现: 综合使用Service,BroadCast,ContentProvider等组件实现后台播放。

  • 播放和暂停、上一首、下一首、停止;
  • 后台播放功能, 按下返回键退出应用后再次打开应用,UI 显示应能与当前的播放状态保持一致;
  • 显示正在播放的歌曲名、作者;
  • 一首歌曲播放完毕能实现自动播放下一首歌曲,并更新界面,显示相关信息;

提交 MusicService 和 MainActivity,运行结果截图。

评分: 1.基本分,60分,实现基本功能,提交的内容完整,条理清晰,可读性好。 2.上一首、下一首;+20分 3.UI销毁后再次打开应能与当前的播放状态保持一致;+20分

在模拟器中上传音乐:

找到路径:C:\Users\17511\Documents\AndroidStudio\DeviceExplorer\emulator-5554\storage\emulated\legacy\Music

MainActivity.java

package com.example.player;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.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;public class MainActivity extends AppCompatActivity implements View.OnClickListener {public static final String CONTROL = "iet.jxufe.cn.android.control";//控制播放、暂停public static final String UPDATE = "iet.jxufe.cn.android.update";//更新界面显示// 定义音乐的播放状态,0x11代表没有播放;0x12代表正在播放;0x13代表暂停int status = 0x11;//获取界面中显示歌曲标题、作者文本框TextView title, author;// 播放/暂停、停止按钮ImageButton play, stop,next,pre;ActivityReceiver activityReceiver;//“启动”服务的intentIntent MusicServiceIntent;@Overrideprotected 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);pre = (ImageButton)this.findViewById(R.id.pre);title = (TextView) findViewById(R.id.title);author = (TextView) findViewById(R.id.author);// 为两个按钮的单击事件添加监听器play.setOnClickListener(this);stop.setOnClickListener(this);next.setOnClickListener(this);pre.setOnClickListener(this);activityReceiver = new ActivityReceiver();IntentFilter filter = new IntentFilter(UPDATE);// 注册BroadcastReceiverregisterReceiver(activityReceiver, filter);MusicServiceIntent = new Intent(this, MusicService.class);//判断权限够不够,不够就给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);}}//获取到权限回调方法@Overridepublic 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;}}public void onClick(View source) {// 创建IntentIntent intent = new Intent(CONTROL);//System.out.println(source.getId());//System.out.println(source.getId() == R.id.play);switch (source.getId()) {// 按下播放/暂停按钮case R.id.play:intent.putExtra("control", 1);Log.d("MusicService","play pressed");break;// 按下停止按钮case R.id.stop:intent.putExtra("control", 2);Log.d("MusicService","stop pressed");break;case R.id.next:intent.putExtra("control", 3);Log.d("MusicService","next pressed");break;case R.id.pre:intent.putExtra("control", 4);Log.d("MusicService","pre pressed");break;}// 发送广播 ,将被Service组件中的BroadcastReceiver接收到sendBroadcast(intent);}// 自定义的BroadcastReceiver,负责监听从Service传回来的广播public class ActivityReceiver extends BroadcastReceiver {public void onReceive(Context context, Intent intent) {// 获取Intent中的update消息,update代表播放状态,默认为-1int update = intent.getIntExtra("update", -1);// 获取Intent中的current消息,current代表当前正在播放的歌曲,默认为-1String songs_title = "";songs_title = intent.getStringExtra("songs_title");String songs_author = "";songs_author = intent.getStringExtra("songs_author");if (update >= 0) {title.setText(songs_title);author.setText(songs_author);}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;}}}@Overrideprotected void onDestroy() {super.onDestroy();unregisterReceiver(activityReceiver);}
}

这样就会自动添加权限

MusicService.java

package com.example.player;import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.MediaPlayer;
import android.os.Environment;
import android.os.IBinder;
import android.util.Log;import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;public class MusicService extends Service {private static final String TAG = "MusicService";private List<Map<String,Object>> musicList = new ArrayList<Map<String,Object>>();private int songsCount = 0;private ServiceReceiver serviceReceiver;private MediaPlayer mPlayer;//当前的状态,0x11 代表没有播放 ;0x12代表 正在播放;0x13代表暂停private int status = 0x11;// 记录当前正在播放的音乐private int current = 0;public MusicService() {}@Overridepublic IBinder onBind(Intent intent) {// TODO: Return the communication channel to the service.throw new UnsupportedOperationException("Not yet implemented");}public void onCreate(){Log.d(TAG,"创建音乐播放服务");// 创建BroadcastReceiverserviceReceiver = new ServiceReceiver();// 创建IntentFilterIntentFilter filter = new IntentFilter(MainActivity.CONTROL);registerReceiver(serviceReceiver, filter);// 创建MediaPlayermPlayer = new MediaPlayer();initSongsData();// 为MediaPlayer播放完成事件绑定监听器mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener(){public void onCompletion(MediaPlayer mp){/* current++;if (current >= songsCount){current = 0;}*/setNextMusic();/* 发送广播通知Activity更改文本框 */Intent sendIntent = new Intent(MainActivity.UPDATE);Map<String,Object> map = musicList.get(current);status = 0x12;sendIntent.putExtra("update", status);sendIntent.putExtra("songs_title",(String)map.get("songs_title"));sendIntent.putExtra("songs_author",(String)map.get("songs_author"));// 发送广播 ,将被Activity组件中的BroadcastReceiver接收到sendBroadcast(sendIntent);// 准备、并播放音乐prepareAndPlay((File)map.get("songs_path"));}});super.onCreate();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.d(TAG,"启动音乐播放服务");//Map<String,Object> map = musicList.get(current);/* 发送广播通知Activity更改图标、文本框 *//*Intent sendIntent = new Intent(MainActivity.UPDATE);sendIntent.putExtra("update", status);sendIntent.putExtra("songs_title", (String)map.get("songs_title"));sendIntent.putExtra("songs_author",(String)map.get("songs_author"));if (status == 0x11){sendIntent.putExtra("songs_title","");sendIntent.putExtra("songs_author","");}// 发送广播 ,将被Activity组件中的BroadcastReceiver接收到sendBroadcast(sendIntent);*/return super.onStartCommand(intent, flags, startId);}private void setNextMusic(){current++;if(current>=songsCount){current = 0;}}private void setPreMusic(){current--;if(current<0){current = songsCount-1;}}// 初始化MediaPlayer歌曲路径,让MediaPlayer进入到准备状态private void initSongsData() {try {//歌曲路径Map<String,Object> map = new HashMap<String, Object>();map.put("songs_title","你是温柔本身");map.put("songs_author","UN1K");map.put("songs_path", new File(Environment.getExternalStorageDirectory(), "/Music/a1.mp3"));musicList.add(map);map = new HashMap<String, Object>();map.put("songs_title","白羊");map.put("songs_author","徐秉龙");map.put("songs_path", new File(Environment.getExternalStorageDirectory(), "/Music/a2.mp3"));musicList.add(map);map = new HashMap<String, Object>();map.put("songs_title","星空");map.put("songs_author","Richard Clayderman .天籁村");map.put("songs_path", new File(Environment.getExternalStorageDirectory(), "/Music/a3.mp3"));musicList.add(map);map = new HashMap<String, Object>();map.put("songs_title","我的一个道姑朋友");map.put("songs_author","双笙");map.put("songs_path", new File(Environment.getExternalStorageDirectory(), "/Music/a4.mp3"));musicList.add(map);songsCount = musicList.size();Log.d(TAG,songsCount+"");//mPlayer.setDataSource(((File)musicList.get(0)).getPath()); // 指定音频文件的路径//mPlayer.prepare(); // 让MediaPlayer进入到准备状态} catch (Exception e) {Log.d(TAG, "设置资源,准备阶段出错");e.printStackTrace();}}public class ServiceReceiver extends BroadcastReceiver {public void onReceive(final Context context, Intent intent){Log.d(TAG,"服务中的广播接收器收到广播");int control = intent.getIntExtra("control", -1);Map<String,Object> map = musicList.get(current);switch (control){// 播放或暂停case 1:// 原来处于没有播放状态if (status == 0x11){// 准备、并播放音乐prepareAndPlay((File) map.get("songs_path"));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){current = 0;//mPlayer.reset();mPlayer.stop();// 停止播放status = 0x11;}break;case 3:setNextMusic();status = 0x12;map = musicList.get(current);prepareAndPlay((File)map.get("songs_path"));break;case 4:// 上一首setPreMusic();status = 0x12;map = musicList.get(current);prepareAndPlay((File) map.get("songs_path"));break;}/*/* 发送广播通知Activity更改图标、文本框 */Intent sendIntent = new Intent(MainActivity.UPDATE);sendIntent.putExtra("update", status);sendIntent.putExtra("songs_title", (String)map.get("songs_title"));sendIntent.putExtra("songs_author",(String)map.get("songs_author"));if (status == 0x11){sendIntent.putExtra("songs_title","");sendIntent.putExtra("songs_author","");}// 发送广播 ,将被Activity组件中的BroadcastReceiver接收到sendBroadcast(sendIntent);}}private void prepareAndPlay(File songsPath){try{mPlayer.reset();//使用MediaPlayer加载指定的声音文件。mPlayer.setDataSource(songsPath.getPath());mPlayer.prepare();// 准备声音mPlayer.start();// 播放}catch (IOException e){e.printStackTrace();}}@Overridepublic void onDestroy() {super.onDestroy();unregisterReceiver(serviceReceiver);}}

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="wrap_content"android:background="@drawable/bg"android:orientation="vertical"tools:context=".MainActivity"><LinearLayoutandroid:layout_width="fill_parent"android:layout_height="fill_parent"android:orientation="horizontal"><ImageButtonandroid:id="@+id/pre"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/selector_btn"android:src="@drawable/previous_button" /><ImageButtonandroid:id="@+id/stop"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/selector_btn"android:src="@drawable/stop" /><ImageButtonandroid:id="@+id/play"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/selector_btn"android:src="@drawable/play" /><ImageButtonandroid:id="@+id/next"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/selector_btn"android:src="@drawable/next_button" /></LinearLayout><LinearLayoutandroid:layout_width="fill_parent"android:layout_height="fill_parent"android:orientation="vertical"><TextViewandroid:id="@+id/title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:textColor="#ffffff"android:layout_gravity="fill_vertical"android:textSize="20sp" /><TextViewandroid:id="@+id/author"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_weight="1"android:layout_gravity="fill_vertical"android:textColor="#ffffff"android:textSize="18sp" /></LinearLayout></LinearLayout>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.player"><uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><serviceandroid:name=".MusicService"android:enabled="true"android:exported="true"></service><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

初始界面:

点击播放:

点击暂停:

点击下一首:

点击停止:

第8章系统服务(简易音频播放器的实现)相关推荐

  1. Python实现简易音频播放器

    1. 需要用到的Python库 pygame tkinter 2. 简易UI设计 audio_player = Tk() audio_player.title('Audio Player v1.0') ...

  2. MediaPlayer 之简易音频播放器

    应当随时学习,学习一切:应当集中全力,以求知道更多,知道一切. 目录结构 1. 前言 2. MediaPlayer介绍 3. MediaPlayer 实战 3.1 简易音频播放器 第一步:布局设置 第 ...

  3. QT——制作简易音频播放器

    应用前提:只需要从阿里云数据库中读取选定的某一条实验数据的音频(.wav),现在的测试版本只是播放本地音频,所以做的这个音频播放器只有6个功能:播放.暂停.音量条.静音.进度条.显示当前播放进度的时间 ...

  4. Android Studio——简易音频播放器

    目的 设计一个具有选歌功能的音频播放器 工具及环境 使用java语言,在Android studio平台上进行开发 功能设计 界面有三个按钮选项,可以停止.播放.暂停音乐.通过选择列表的音乐,播放相应 ...

  5. 微信小程序简易音频播放器(wx.getBackgroundAudioManager())

    开发工具:微信开发者工具 源代码(百度网盘:)链接: 提取码:ldb9 注意:如果点击播放没反应,或者爆红,则需要更换js中的视频地址 第一步.首先要在app.json里设置: "requi ...

  6. AudioPlayer-简易音频播放器

    AudioPlayer 该工程是一个基于Unity2018.3.13开发的简易音频播放器,支持歌词同步+音频可视化+MV同步-- 前言 在我Unity工作的第一年里,通过学习和研究积累了一些比较有意思 ...

  7. JavaScript + Audio API自制简易音乐播放器(详细完整版、小白都能看懂)

    JavaScript + Audio API自制简易音乐播放器(详细完整版) ** 音乐播放器的功能清单如下: ** 1.点击暂停按钮,歌曲暂停 2.点击播放按钮,歌曲播放 3.单曲循环与取消单曲循环 ...

  8. 用html做成的音频播放器,HTML5制作酷炫音频播放器插件图文教程

    上图便是这个音频播放器的UI界面图,里面还隐藏了一个歌曲的播放列表.整个播放器的UI除了大背景的人像图和歌曲的星星评分使用了图片其他全部由CSS和font-face绘制而成,看上去有难度的地方就只有C ...

  9. 安卓平板倍速_推荐:安卓上本地音频播放器,可实现5秒快进快退和倍速播放...

    前一篇文章推荐过一个app,但那app没倍速播放功能.我又找到了一个更完美的app 安卓手机上我自己需要这样一款app,主要用来听电子书,知识音频等.需要能实现快进快退几秒钟的以及倍速播放功能.这功能 ...

最新文章

  1. Failed to open zip file. Gradle‘s dependency cache may be corrupt (xx)
  2. mysql 客户端提示“Cannot proceed because system tabl...
  3. 机器学习入门:线性回归及梯度下降
  4. codeforce gym 100548H The Problem to Make You Happy
  5. java面试题总结(三)----本文都是笔试题,值得学习
  6. java用户角色权限管理 只显示姓_扩展RBAC用户角色权限设计方案
  7. python distance matrix_Python 矩阵转置的几种方法小结
  8. 电源大师课笔记 2.9
  9. yuicompressor java_YUI Compressor
  10. 北京市昌平区卫星地图离线包下载
  11. HBuilderX连接夜神模拟器
  12. CodeForces - 558DGuess Your Way Out! II(map 扫描线)
  13. b java 之 serviceLoader详解 serviceLoader.load(XXX.class)
  14. 【python】【爬虫】爬取电子书《红星照耀中国》
  15. 使用 SAP UI5 Smart Chart 控件轻松绘制十数种不同类型的专业图表试读版
  16. 【SLAM】视觉SLAM:一直在入门,从未到精通
  17. 智能CAN总线隔离中继器
  18. 检索大写字母 c语言,c语言梦工厂梅丽题目含答案.docx
  19. IDC许可证是什么,如何办理IDC增值电信业务经营许可证年报
  20. 简单实用的logger-Blackbird

热门文章

  1. s-sar命令(System Activity Reporter系统活动情况报告)
  2. nginx反向代理原理及配置详解
  3. 云计算时代的数据库运行
  4. Scrapy 学习笔记(-)
  5. 《Java 8 实战》(二)—— Lambda
  6. 统计文件种类数+获取子shell返回值的其它方法
  7. 我现在的vimrc配置文件
  8. 男人最不该做的7件事
  9. Windows下SVN权限配置过程详解
  10. 六步使用ICallbackEventHandler实现无刷新回调