Service 的两种启动方式,以及在音乐播放中的使用

 首先,简要介绍一下service

   service就是android系统中的服务,它有这么几个特点:它无法与用户直接进行交互、它必须由用户或者其他程序显式的启动、它的优先级比较高, 它比处于前台的应用优先级低,但是比后台的其他应用优先级高,这就决定了当系统因为缺少内存而销毁某些没被利用的资源时,它被销毁的概率很小。

 

bindService是绑定Service服务,执行service服务中的逻辑流程。

service通过Context.startService()方法开始,通过Context.stopService()方法停止;也可以通过Service.stopSelf()方法或者Service.stopSelfResult()方法来停止自己。只要调用一次stopService()方法便可以停止服务,无论之前它被调用了多少次的启动服务方法。

客户端建立一个与Service的连接,并使用此连接与Service进行通话,通过Context.bindService()方法来绑定服务,Context.unbindService()方法来关闭服务。多个客户端可以绑定同一个服务,如果Service还未被启动,bindService()方法可以启动服务。

    startService()和bindService()两种模式是完全独立的。你可以绑定一个已经通过startService()方法启动的服务。例如:一 个后台播放音乐服务可以通过startService(intend)对象来播放音乐。可能用户在播放过程中要执行一些操作比如获取歌曲的一些信息,此时 activity可以通过调用bindServices()方法与Service建立连接。这种情况下,stopServices()方法实际上不会停止 服务,直到最后一次绑定关闭。

    这2种模式不是完全分离的。你可以可以绑定到一个通过startService()启动的服务。如 一个intent想要播放音乐,通过startService() 方法启动后台播放音乐的service。然后,也许用户想要操作播放器或者获取当前正在播放的乐曲的信息,一个activity就会通过 bindService()建立一个到此service的连接. 这种情况下 stopService() 在全部的连接关闭后才会真正停止service。

   

bindService启动流程

context.bindService()  ——> onCreate()  ——> onBind()  ——> Service running  ——> onUnbind()  ——> onDestroy()  ——> Service stop

onBind()将返回给 客户端一个IBind接口实例,IBind允许客户端回调服务的方法,比如得到Service的实例、运行状态或其他操作。这个时候把调用者 (Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用 onUnbind->onDestroy相应退出。

所以调用bindService的生命周期为:onCreate --> onBind(只一次,不可多次绑定) --> onUnbind --> onDestory。

在Service每一次的开启关闭过程中,只有onStart可被多次调用(通过多次startService调用),其他onCreate,onBind,onUnbind,onDestory在一个生命周期中只能被调用一次。

 

整个生命周期

service 的整个生命周期是在onCreate()和onDestroy()方法之间。和activity一样,在onCreate()方法里初始化,在 onDestroy()方法里释放资源。例如,一个背景音乐播放服务可以在onCreate()方法里播放,在onDestroy()方法里停止。

活动的生命周期

service 的活动生命周期是在onStart()之后,这个方法会处理通过startServices()方法传递来的Intent对象。音乐service可以通 过开打intent对象来找到要播放的音乐,然后开始后台播放。注: service停止时没有相应的回调方法,即没有onStop()方法,只有onDestroy()销毁方法。

任何服务无论它怎样建立,默认客户端都可以连接,所以任何service都能够接收onBind()和onUnbind()方法

onCreate()方法和onDestroy()方法是针对所有的services,无论它们是否启动,通过Context.startService()和Context.bindService()方法都可以访问执行。然而,只有通过startService()方法启动service服务时才会调用onStart()方法。

 

如果一个service允许别人绑定,那么需要实现以下额外的方法:

      IBinder onBind(Intent intent)

      boolean onUnbind(Intent intent)

      void onRebind(Intent intent)

onBind()回调方法会继续传递通过bindService()传递来的intent对象

onUnbind()会处理传递给unbindService()的intent对象。如果service允许绑定,onBind()会返回客户端与服务互相联系的通信句柄(实例)。

如果建立了一个新的客户端与服务的连接,onUnbind()方法可以请求调用onRebind()方法。

 

经过上面的简介,那么,当我们需要实现一个音乐服务,在状态栏包含通知,同时在很多界面都可以调用音乐服务器的进度,音乐名等信息的功能时,我们已经有思路了,那就是用startservice 开启一个音乐服务,然后在需要获取信息的界面,采用bindservice 获取音乐信息,需要注意的是,我们在此处,启动音乐服务不能采用bindservice ,因为此模式启动,当首次绑定服务的界面销毁时,服务也跟随销毁了。

 

如下

/**
 * 佛祖保佑        永无BUG
 * 佛曰:
 * 程序园里程序天,程序天里程序员;
 * 程序猿人写程序,又拿程序换肉钱。
 * 肉饱继续桌前坐,饱暖还是桌前眠;
 * 半迷半醒日复日,码上码下年复年。
 * 但愿叱咤互联世,不愿搬砖码当前;
 * 诸葛周瑜算世事,我算需求得加钱。
 * 别人笑我忒直男,我说自己是程猿;
 * 但见成都府国内,处处地地程序员。
 * Created by 水东流 on 2018/8/13.
 */

public class MusicService extends Service {
    List musicPath = new ArrayList<>();//播放地址
    //标记当前歌曲的序号
    private int index = 0;

    public MusicService() {
        iniMediaPlayerFile(0);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    /*设置锁屏界面*/
    @Override
    public void onCreate() {
        super.onCreate();
      /*  receiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (intent.getAction() == Intent.ACTION_SCREEN_OFF) {
                    Log.e(TAG, "收到锁屏广播");
                    Intent lockscreen = new Intent(MusicService.this, MusicSuoPingActivity.class);
                    lockscreen.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(lockscreen);
                }
            }
        };
        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_SCREEN_OFF);
        registerReceiver(receiver, filter);*/
    }

    public class MyBinder extends Binder {
        /**
         * 是否正在播放
         */
        public boolean isPlay() {
            if (mMediaPlayer.isPlaying()) {
                return true;
            }
            return false;
        }

        /**
         * 更换播放地址
         *
         * @param url
         */
        public void changeUrl(List url) {
            musicPath = url;
            if (mMediaPlayer != null) {
                mMediaPlayer.reset();
            }
            index = 0;
            iniMediaPlayerFile(index);
        }

        /**
         * 播放音乐
         */
        public void playMusic() {
            if (!mMediaPlayer.isPlaying()) {
                //如果还没开始播放,就开始
                mMediaPlayer.start();
            }
        }

        /**
         * 暂停播放
         */
        public void pauseMusic() {
            if (mMediaPlayer.isPlaying()) {
                //如果还没开始播放,就开始
                mMediaPlayer.pause();
            }
        }

        /**
         * reset
         */
        public void resetMusic() {
            if (!mMediaPlayer.isPlaying()) {
                //如果还没开始播放,就开始
                mMediaPlayer.reset();
                iniMediaPlayerFile(index);
            }
        }

        /**
         * 关闭播放器
         */
        public void closeMedia() {
            if (mMediaPlayer != null) {
                mMediaPlayer.stop();
                mMediaPlayer.release();
            }
        }

        /**
         * 下一首
         */
        public void nextMusic() {
            if (mMediaPlayer != null && index < musicPath.size() && index >= 0) {
                //切换歌曲reset()很重要很重要很重要,没有会报IllegalStateException
                mMediaPlayer.reset();
                //这里的if只要是为了不让歌曲的序号越界
                if (index == musicPath.size() - 1) {
                    index = 0;
                } else {
                    index = index + 1;
                }
                iniMediaPlayerFile(index);
                playMusic();
            }
        }

        /**
         * 上一首
         */
        public void preciousMusic() {
            if (mMediaPlayer != null && index < musicPath.size() && index > 0) {
                mMediaPlayer.reset();
                if (index == 1) {
                    index = musicPath.size() - 1;
                } else {
                    index = index - 1;
                }
                iniMediaPlayerFile(index);
                playMusic();
            }
        }

        /**
         * 获取歌曲长度
         **/
        public int getProgress() {
            return mMediaPlayer.getDuration();
        }

        /**
         * 获取播放位置
         */
        public int getPlayPosition() {
            return mMediaPlayer.getCurrentPosition();
        }

        /**
         * 播放指定位置
         */
        public void seekToPositon(int msec) {
            mMediaPlayer.seekTo(msec);
        }


    }

    /**
     * 添加file文件到MediaPlayer对象并且准备播放音频
     */
    private void iniMediaPlayerFile(int position) {
        if (musicPath == null || musicPath.size() == 0) return;
        //获取文件路径
        try {
            //此处的两个方法需要捕获IO异常
            //设置音频文件到MediaPlayer对象中
            mMediaPlayer.setDataSource(musicPath.get(position));
            //让MediaPlayer对象准备
            mMediaPlayer.prepare();
        } catch (IOException e) {
            Log.d(TAG, "设置资源,准备阶段出错");
            e.printStackTrace();
        }
    }

    private BroadcastReceiver receiver;
    //初始化MediaPlayer
    public MediaPlayer mMediaPlayer = new MediaPlayer();
    private static final String TAG = "MediaService";
    private MyBinder mBinder = new MyBinder();

}

 

启动界面代码

/**启动音乐服务*/
        /** 单击按钮时启动服务 */
        Intent intent = new Intent(mcontext,
                MusicService.class);
        startService(intent);

获取音乐服务信息界面的代码

/**
 * 绑定
 */
private void initMusic() {
    mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mMyBinder = (MusicService.MyBinder) service;
            viewHolder.seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                    //这里很重要,如果不判断是否来自用户操作进度条,会不断执行下面语句块里面的逻辑,然后就会卡顿卡顿
                    if (fromUser) {
                        mMyBinder.seekToPositon(seekBar.getProgress());
                    }
                }

                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {

                }

                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {

                }
            });
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };
    MediaServiceIntent = new Intent(mcontext, MusicService.class);
    bindService(MediaServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
}

绑定之后就可以通过 mMyBinder来获取和操作服务中信息数据了

case R.id.precious:
    mMyBinder.preciousMusic();
    break;
case R.id.play:
    if (mMyBinder.isPlay()) {
        mMyBinder.pauseMusic();
        viewHolder.play.setImageResource(R.mipmap.zant1);
    } else {
        mMyBinder.playMusic();
        viewHolder.play.setImageResource(R.mipmap.zant2);
    }
    break;
case R.id.next:
    mMyBinder.nextMusic();
    break;

 

 

 

你可能感兴趣的:(android)