android学习笔记----简易音乐播放器原理
发布日期:2021-06-30 19:55:58
浏览次数:103
分类:技术文章
本文共 8587 字,大约阅读时间需要 28 分钟。
只是熟悉MediaPlayer用法
简易功能是:播放暂停,停止后从头播放,进度条跟随音乐进度,拖动进度条音乐也随之改变播放进度。
网上音乐接口百度能够搜到,这里就只写一点原理。
官方文档地址:
Demo地址:
状态图:
运行效果图:
MainActivity.java
import android.Manifest;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.content.pm.PackageManager;import android.os.Bundle;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.support.annotation.NonNull;import android.support.v4.app.ActivityCompat;import android.support.v4.content.ContextCompat;import android.support.v7.app.AppCompatActivity;import android.util.Log;import android.view.View;import android.widget.SeekBar;import android.widget.Toast;public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; private Iservice iservice; private MyConn myConn; public static Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { // 获取携带的数据 Bundle data = msg.getData(); // 获取歌曲的总时长和当前进度 int duration = data.getInt("duration"); int currentPosition = data.getInt("currentPosition"); // 设置seekbar进度 sbar.setMax(duration); sbar.setProgress(currentPosition); } }; private static SeekBar sbar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 混合方式开启服务 Intent intent = new Intent(this, MusicSevice.class); startService(intent); // 调用bindService,为了回去定义的中间人对象 myConn = new MyConn(); bindService(intent, myConn, BIND_AUTO_CREATE); // 找到seekbar,设置进度 sbar = findViewById(R.id.seekBar); // 4.给seekBar设置监听事件 sbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { // 当进度改变的时候调用 @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { } // 当开始拖动的时候调用 @Override public void onStartTrackingTouch(SeekBar seekBar) { } // 当拖动停止的时候调用 @Override public void onStopTrackingTouch(SeekBar seekBar) { iservice.callSeekTo(seekBar.getProgress()); } }); } @Override protected void onDestroy() { super.onDestroy(); // 当activity销毁的时候调用,为了不报异常 unbindService(myConn); Log.d(TAG, "onDestroy: "); } // 播放 public void click(View view) { // 这里播放tomcat服务器的音乐不需要权限,如果是播放/mnt/sdcard/...需要权限,因为测试的时候在这个目录,所以这里写了权限 applyPermissions(Manifest.permission.READ_EXTERNAL_STORAGE); } private void applyPermissions(String readExternalStorage) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{readExternalStorage}, 1); } else { iservice.callPlayMusic(); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode) { case 1: if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { iservice.callPlayMusic(); } else { Toast.makeText(this, "权限被拒绝,请在设置手动打开", Toast.LENGTH_SHORT).show(); } break; } } // 暂停 public void click2(View view) { iservice.callPauseMusic(); } public void click3(View view) { iservice.callStopMusic(); } // 监听服务的状态 private class MyConn implements ServiceConnection { @Override public void onServiceConnected(ComponentName name, IBinder service) { iservice = (Iservice) service; } @Override public void onServiceDisconnected(ComponentName name) { } }}
MusicSevice.java
import android.app.Service;import android.content.Intent;import android.media.MediaPlayer;import android.os.Binder;import android.os.Bundle;import android.os.IBinder;import android.os.Message;import android.util.Log;import java.io.IOException;import java.util.Timer;import java.util.TimerTask;public class MusicSevice extends Service { private static final String TAG = "MusicSevice"; private MediaPlayer mediaPlayer; private Timer timer; private TimerTask task; public MusicSevice() { Log.d(TAG, "构造: "); initMediaPlayer(); } // 把定义的中间人返回 @Override public IBinder onBind(Intent intent) { return new MyBinder(); } // 服务已开启就执行这个方法 @Override public void onCreate() { Log.d(TAG, "onCreate: "); super.onCreate(); } @Override public void onDestroy() { super.onDestroy(); } // 播放音乐的方法 public void playMusic() { // 准备播放 // mediaPlayer.prepare(); if (mediaPlayer == null) { Log.d(TAG, "mediaplayer确实为null"); initMediaPlayer(); mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { // 准备完成的监听器 @Override public void onPrepared(MediaPlayer mp) { // 开始播放 mediaPlayer.start(); // 更新进度条 updateSeekBar(); } }); } if (!mediaPlayer.isPlaying()) { Log.d(TAG, "没有正在播放,开始操作"); mediaPlayer.start(); // 更新进度条 updateSeekBar(); Log.d(TAG, "音乐播放了"); } } private void initMediaPlayer() { // 初始化mediaplayer try { mediaPlayer = new MediaPlayer(); // 设置要播放的资源位置path,可以是网络路径,也可以是本地路径 // /mnt/sdcard/yinyue.mp3 mediaPlayer.setDataSource("http://192.168.164.1:8080/yinyue.mp3"); mediaPlayer.prepareAsync(); } catch (IOException e) { e.printStackTrace(); } } private void updateSeekBar() { // 获取当前歌曲总长度 final int duration = mediaPlayer.getDuration(); // 使用Timer 定时器去获取当前进度 timer = new Timer(); task = new TimerTask() { @Override public void run() { // 一秒钟获取一次当前进度 int currentPosition = mediaPlayer.getCurrentPosition(); // 拿到我们在MainActivity创建的handler发消息,消息可以携带数据 Message message = Message.obtain(); //obj只能携带一个数据 Bundle bundle = new Bundle(); // map bundle.putInt("duration", duration); bundle.putInt("currentPosition", currentPosition); message.setData(bundle); // 发送一条消息,MainActivity里面的handlemessage就会执行 MainActivity.handler.handleMessage(message); } }; // 100ms后每间隔1s、执行一次run方法 timer.schedule(task, 100, 1000); // 设置播放完成的监听 mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { Log.d(TAG, "歌曲播放完成"); timer.cancel(); task.cancel(); } }); } // 实现指定播放的位置 public void seekTo(int position) { mediaPlayer.seekTo(position); } // 暂停音乐的方法 public void pauseMusic() { if (mediaPlayer.isPlaying()) { // 暂停音乐 mediaPlayer.pause(); timer.cancel(); Log.d(TAG, "音乐暂停了"); } } public void stopMusic() { mediaPlayer.stop(); // 如果不取消定时任务,mediaplayer停止就崩了 timer.cancel(); task.cancel(); mediaPlayer = null; } // 在服务的内部定义一个中间人对象(IBinder) private class MyBinder extends Binder implements Iservice { @Override public void callPlayMusic() { playMusic(); } @Override public void callPauseMusic() { pauseMusic(); } @Override public void callStopMusic() { stopMusic(); } @Override public void callSeekTo(int position) { seekTo(position); } }}
Iservice.java
public interface Iservice { // 把想暴露的方法都定义在接口中 public void callPlayMusic(); public void callPauseMusic(); public void callStopMusic(); public void callSeekTo(int position);}
activity_main.xml
=========================Talk is cheap, show me the code=========================
转载地址:https://liuchenyang0515.blog.csdn.net/article/details/82624073 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
表示我来过!
[***.240.166.169]2024年05月03日 00时39分49秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
HDU - 2068 RPG的错排 (错排+组合数)
2019-04-30
CodeForces 591C Median Smoothing(思维 模拟)
2019-04-30
升级yosemite后java出错的解决
2019-04-30
mac || Linux 命令行下实现批量重命名
2019-04-30
java常用类 String面试题
2019-04-30
Windows10下的powershell美化教程
2019-04-30
利用ffmpeg合并音频和视频
2019-04-30
刷好老毛子系统进不了老毛子系统后台的解决办法
2019-04-30
Parallels Desktop 16 不能联网的解决办法
2019-04-30
SLAM中TUM数据集更改图片名字
2019-04-30
手把手教你--jquery chosen插件的使用和API(html下拉框美化)
2019-04-30
手把手教你--JAVA微信支付(H5支付)
2019-04-30
solr修改schema文件(solr修改配置文件)
2019-04-30
Bootstrap datetimepicker日期时间插件使用方法(日期时间选择器)
2019-04-30
字体图标库(Font Awesome)的使用--绝佳的图标字体库和CSS框架
2019-04-30