【达内课程】音乐播放器2.0(中)

接着 音乐播放器2.0(上) 对 音乐播放器1.0做改造。把音乐播放改为使用 Service,实现可以后台播放音乐。

开发步骤是按照 【达内课程】Service 中总结的开发步骤做的。

1、新建 PlayMusicService
新建 PlayMusicService 继承 Service,放到 Service 文件夹下。

public class PlayMusicService extends Service {
    public PlayMusicService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
}

检查下 AndroidManifest.xml 中是否注册了

<service
	android:name=".Service.PlayMusicService"
	android:enabled="true"
	android:exported="true"/>

2、创建 IMusicPlayer 接口,定义要实现的方法
创建 IMusicPlayer 接口,并在接口中定义由 Service 实现功能,但由 Activity 调用的方法。例如点击一个播放按钮,当然是由 Activity 调用的,但是为了保证优先级,这些方法应该在 Service 中定义。

public interface IMusicPlayer<T> {
    //播放歌曲
    void play();

    /**
     * 播放指定position对应的歌曲
     *
     * @param position
     */
    void play(int position);

    //暂停歌曲
    void pause();

    //下一首歌曲
    void next();

    //上一首歌曲
    void previous();

    /**
     * 获取当前播放歌曲的总时长
     *
     * @return 当前播放歌曲的总时长
     */
    int getDuration();

    /**
     * 获取当前播放到的位置
     *
     * @return 当前播放到的位置 单位:毫秒
     */
    int getCurrentPosition();

    /**
     * 获取当前正在播放的歌曲的索引
     */
    int getCurrentMusicPosition();

    /**
     * 获取当前播放歌曲的播放状态
     *
     * @return 当前播放歌曲的播放状态,true:正在播放;false:停止播放
     */
    boolean isPlaying();
}

这些方法都是我们在 MainActivity 中使用的。如果一次性写不完可以用到再添加。把这个文件放在Util(Utility工具文件夹)或Core(核心文件夹)中。

3、在 PlayMusicService 中创建内部类 IBinder类,为和 Activity 连接做准备
在 PlayMusicService 中创建内部类 IBinder 类,继承自 Binder,实现 IMusicPlayer接口,并实现接口中的方法。

然后 PlayMusicService 的onBind()方法中创建 InnerBiner 对象,并作为该方法的返回值。

public class PlayMusicService extends Service {
    public PlayMusicService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        InnerBinder binder = new InnerBinder();
        return binder;
    }

    private class InnerBinder extends Binder implements IMusicPlayer {

        @Override
        public void play() {
            Log.d("Music", "由Service调用play()");
        }

        @Override
        public void play(int position) {
            Log.d("Music", "由Service调用play(int position)");
        }

        @Override
        public void pause() {

        }

        @Override
        public void previous() {

        }

        @Override
        public void next() {

        }

        @Override
        public int getCurrentMusicPosition() {
            return 0;
        }

        @Override
        public int getCurrentPosition() {
            return 0;
        }

        @Override
        public int getDuration() {
            return 0;
        }

        @Override
        public boolean isPlaying() {
            return false;
        }
    }
}

4、MainActivity 中绑定 Service
MainActivity 中创建内部类 InnerServiceConnection,实现 ServiceConnection 接口。声明 IMusicPlayer 类型的全局变量 player,并在 InnerServiceConnection 中 onServiceConnected()方法中通过第二个参数直接赋值,并强制转换类型。

/**
     * 与Service实现绑定时建立的连接对象
     * 声明成内部类或接口类型都可以
     */
    private ServiceConnection conn;
    /**
     * 调用Service中实现的功能的对象
     */
    private IMusicPlayer player;


    private class InnerServiceConnection implements ServiceConnection {

        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            player = (IMusicPlayer)iBinder;
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {

        }
    }

onCreate()方法中增加绑定 Service 的方法:bindService()

		//绑定Service
        Intent intent = new Intent(this, PlayMusicService.class);
        conn = new InnerServiceConnection();
        bindService(intent,conn,BIND_AUTO_CREATE);

5、MainActivity 中调用 PlayMusicService 中的方法

MainActivity 中需要调用 PlayMusicService 中的方法时,直接用 player 调用即可。所以可以把 onClick 中代码改为:

//按钮监听
    private class InnerClassOnClickListener implements View.OnClickListener {
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.ib_play:
                    if (player.isPlaying()) {
                        player.pause();
                    } else {
                        player.play();
                    }
                    break;
                case R.id.ib_previous:
                    player.previous();
                    break;
                case R.id.ib_next:
                    player.next();
                    break;
            }
        }
    }

6、MainActivity 中的 onDestroy 中解除与 Service 的绑定

@Override
    protected void onDestroy() {
        //解除与Service的绑定
        unbindService(conn);
        //停止更新进度的线程
        stopThread();
        //释放资源
        mediaPlayer.release();
        mediaPlayer = null;

        super.onDestroy();
    }

现在运行程序,点击播放按钮,输出日志如下
在这里插入图片描述
7、PlayMusicService 中完善播放器的方法
PlayMusicService 中完善播放器的方法,把 MainActivity 中的相应方法、相关变量拿过来,稍作修改。有些改变页面上图标的地方,例如 play()的时候会把暂停按钮改成播放按钮,这个操作可以放在 Activity 的 onClick() 事件中,这样写比较方便。

内部类 InnerBinder 直接调用上面写的方法,同时在 onDestroy 方法执行时释放相关资源。

相应的 MainActivity 中的相应方法、相关变量都可以删除了。调用方法的地方可以使用刚刚声明的 IMusicPlayer 类型的全局变量 player 直接调用。

8、在 MainActivity 中开启一个线程,查询 service 中状态
显示歌曲的时候 Activity 是主动方,Service 没有办法主动告诉 Activity 自己目前播放的是哪首歌,因此应该在 MainActivity 中开启一个线程,每隔 1 秒查询 Service 中状态。同时增加开启线程,关闭线程的方法。可以对之前的 UpdateProgressThread 进行修改。

把格式化时间的方法单独放到一个 CommonUtil 的工具类中方便使用。

在点击播放/暂停,上一首,下一首等按钮时,开启或关闭相应线程即可,同时在onDestroy()方法中停止线程。

这部分代码先不放了,有点繁琐,下一章直接上完整代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值