《第一行代码Android》笔记十:本地Service的onBind使用简介

时间:2024-03-31 11:32:54

onBind方法

在Android中写Service时总有一个onBind方法, 默认情况下返回null, 在最新的Android Studio中是抛出一个异常. 
之所以有这个方法, 是因为在Activity中启动Service之后, 他俩就没有联系了, 这个方法可以让我们给Service发消息, 让其执行相关的操作.

写作原因

最近看书看到了Service部分, 里面恰好讲到了onBind. 我突然想起来在UC实习的时候有做过一个app, 里面有个需求是在后台播放音乐, 我记得当时也是用onBind返回的对象操作Service控制MediaPlayer. 不同的地方在于, 我当时使用了AIDL, 而我正在看的这本书没有用这个. 
当时用AIDL完成那个控制后台播放音乐的功能没有遇到多少困难, 唯独感觉这种实现方法太麻烦了, 有点不科学. 现在看了这本书才发现好像我做了一件大炮打蚊子的事情. 
查了一下AIDL, 那是给IPC准备的, 如果需要把自己的服务暴露给其他的app调用, 就需要用AIDL. 我这边自己控制自己的服务, 根本不需要IPC, 是我自己弄麻烦了.

后台播放音乐

这次的例子是后台播放音乐, 需要在服务中完成对MediaPlayer的所有控制, 所以需要使用到onBind方法. 
关于MediaPlayer, 有个很复杂的状态图, 如果要控制它就一定要看官方文档, 这不是本文的主要目标, 所以我不涉及这方面内容, 仅仅演示一下如何使用onBind.

Service实现

创建一个继承自ServiceMusicPlayer, 然后在里面再定义一个继承自BinderPlayerBinder类. 注意设为public, 然后还需要声明一个类型为PlayerBinder的成员变量mBinder, 可以在onCreate中实例化, 这就是我们要在onBind中返回的东西. 
PlayerBinder类中的方法就是我们可以控制MusicPlayer执行的方法.

public class MusicPlayer extends Service implements MediaPlayer.OnErrorListener, MediaPlayer.OnPreparedListener {

    private PlayerBinder mBinder;

    private MediaPlayer mMediaPlayer = null;

    public MusicPlayer() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mBinder = new PlayerBinder();
        mMediaPlayer = new MediaPlayer();
        mMediaPlayer.setWakeMode(this, PowerManager.PARTIAL_WAKE_LOCK);
        mMediaPlayer.setOnPreparedListener(this);
    }

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

    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
        mp.reset();
        return true;
    }

    @Override
    public void onPrepared(MediaPlayer mp) {
        mMediaPlayer.start();
    }

    public class PlayerBinder extends Binder {

        public void play() {
            try {
                mMediaPlayer.reset();
                mMediaPlayer.setDataSource(getAssets().openFd("roadsuntraveled.mp3").getFileDescriptor());
                mMediaPlayer.prepareAsync();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        public void pause() {
            if (mMediaPlayer.isPlaying()) {
                mMediaPlayer.pause();
            }
        }

        public void resume() {
            if (!mMediaPlayer.isPlaying()) {
                mMediaPlayer.start();
            }
        }

        public void stop() {
            mMediaPlayer.stop();
        }

        public void release() {
            mMediaPlayer.release();
        }
    }
}

我在src/main/assets下放了一个叫roadsuntraveled.mp3的文件, 这是我们播放的本地音频. 如果使用eclipse, 那么就放在assets/目录下. 
注意如果照搬这个代码, 还需要在AndroidManifest.xml中添加<service><uses-permission android:name="android.permission.WAKE_LOCK" />

Activity

Activity中除了一些控制用的控件之外, 最主要的是一个类型为MusicPlayer.PlayerBinder的成员变量, 和一个类型为ServiceConnection的成员变量. 
其中ServiceConnection在启动服务时传入, 在它的方法中我们获取Binder, 并赋值给mPlayerBinder. 注意启动服务是调用bindService.

public class MainActivity extends ActionBarActivity implements View.OnClickListener {

    private static final String TAG = "MainActivity";

    private MusicPlayer.PlayerBinder mPlayerBinder;

    private Button start;
    private Button resume;
    private Button pause;
    private Button stop;

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mPlayerBinder = (MusicPlayer.PlayerBinder) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(TAG, "onServiceDisconnected");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        start = (Button) findViewById(R.id.start);
        resume = (Button) findViewById(R.id.resume);
        pause = (Button) findViewById(R.id.pause);
        stop = (Button) findViewById(R.id.stop);
        start.setOnClickListener(this);
        resume.setOnClickListener(this);
        pause.setOnClickListener(this);
        stop.setOnClickListener(this);
        Intent serviceIntent = new Intent(this, MusicPlayer.class);
        bindService(serviceIntent, mConnection, BIND_AUTO_CREATE);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mPlayerBinder.release();
        unbindService(mConnection);

    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.start:
                mPlayerBinder.play();
                break;
            case R.id.resume:
                mPlayerBinder.resume();
                break;
            case R.id.pause:
                mPlayerBinder.pause();
                break;
            case R.id.stop:
                mPlayerBinder.stop();
                break;
            default:
                break;
        }
    }
}

随后我们通过mPlayerBinder就可以完成对Service的控制了. 可以通过四个按钮控制音频的播放, 暂停等. 
最后不要忘了unBindService.

另外本人还开设了个人公众号:JiandaoStudio ,会在公众号内定期发布行业信息,以及各类免费代码、书籍、大师课程资源。

                                                  《第一行代码Android》笔记十:本地Service的onBind使用简介

                                            

扫码关注本人微信公众号,有惊喜奥!公众号每天定时发送精致文章!回复关键词可获得海量各类编程开发学习资料!

例如:想获得Python入门至精通学习资料,请回复关键词Python即可。