android学习笔记----简易音乐播放器原理
发布日期:2021-06-30 19:55:58 浏览次数:102 分类:技术文章

本文共 8587 字,大约阅读时间需要 28 分钟。

只是熟悉MediaPlayer用法

简易功能是:播放暂停,停止后从头播放,进度条跟随音乐进度,拖动进度条音乐也随之改变播放进度。

网上音乐接口百度能够搜到,这里就只写一点原理。

官方文档地址:

Demo地址:

状态图:

MediaPlayer State diagram

运行效果图:

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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:448. Find All Numbers Disappeared in an Array(找到所有数组中消失的数字)
下一篇:198. House Robber(打家劫舍)(求不相邻的位置上的数字之和的最大值)

发表评论

最新留言

关注你微信了!
[***.104.42.241]2024年04月23日 10时11分44秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章