21、绑定服务

绑定服务的实现
什么时候需要使用绑定服务呢?我的理解是调用者在启动完服务后,还需要以后与服务打交道,还要控制服务,而不是像启动服务一样任服务自由自在不受控制。常见的一个场景,Service播放音乐,界面上有上一曲,下一曲、暂停、播放等按钮,通过这些按钮还可以控制Service操作,这种情景就是使用的绑定,本篇博客的例子也将实现一个简单的demo。
1.定义服务
绑定服务,需要重写onBind()方法,并且返回一个IBinder对象,该IBinder客户端再绑定服务成功后可以获取一个该对象,因此客户端可以通过IBinder来控制服务。IBinder是一个接口,一般我们不会直接实现该接口,而是会继承Binder类,Binder类实现了IBinder类。
下面是该播放服务的示例:

  • 播放音乐服务

*/
public class PlayMusicService extends Service {
public PlayMusicService() {
}
public class PlayMusicBinder extends Binder {

    /**
     * 播放音乐
     */
    public void play() {

        playMusic();

    }

    /**
     * 暂停播放
     */
    public void pause() {
        pauseMusic();
    }

    /**
     * 暂停播放
     */
    public void stop() {

        stopMusic();

    }

}

private PlayMusicBinder mBinder = new PlayMusicBinder();

private MediaPlayer mediaPlayer;

@Override
public void onCreate() {
    super.onCreate();
    mediaPlayer = MediaPlayer.create(this, R.raw.diamonds);
}

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

@Override
public void onDestroy() {
    super.onDestroy();
    if (mediaPlayer != null)
        mediaPlayer.release();
}

private void playMusic() {
    mediaPlayer.start();
}

private void pauseMusic() {
    mediaPlayer.pause();
}

private void stopMusic() {
    mediaPlayer.stop();
}   }

其中PlayMusicBinder继承自Binder类,并且提供了三个接口,分别是播放音乐、暂停音乐以及停止播放;在onBind()方法中返回这样一个实例。播放音乐用到了MediaPlayer,音乐文件直接直接放在了res/raw/目录下。至此,服务端就完成了,主要工具就是编写一个Binder类提供给客户端操作的接口。
从上面可以看到,定义服务端主要包括两步:

  1. 扩展Binder类,实现接口
  2. 在onBind()方法返回一个IBinder实例
    2.定义调用者(Activity)
    在定义完服务端后,再来定义客户端,bindService方法中第二个参数是一个ServiceConnection接口,当服务连接成功以及失去连接时会分别回调两个方法。下面是Activity的定义:

public class PlayMusicActivity extends AppCompatActivity {

private PlayMusicService.PlayMusicBinder musicBinder;

private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        //在服务连接成功后保存PlayeMusicBinder对象,控制服务端
        musicBinder = (PlayMusicService.PlayMusicBinder) service;
    }
    @Override
    public void onServiceDisconnected(ComponentName name) {
        musicBinder = null;
    }
};
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_play_music);
}
@Override
protected void onStart() {
    super.onStart();
    bindService(new Intent(this, PlayMusicService.class), connection, Service.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
    super.onDestroy();
    unbindService(connection);
}
public void playMusic(View view) {
    if (musicBinder != null)
        musicBinder.play();
}
public void pauseMusic(View view) {
    if (musicBinder != null)
        musicBinder.pause();
}
public void stopMusic(View view) {
    if (musicBinder != null)
        musicBinder.stop();
}   }

从上面的代码可以看出,在onStart中绑定服务,一旦服务绑定成功,则保存PlayMusicBinder对象。界面上有三个按钮,分别是播放、暂停和停止,接下来就可以控制后台服务播放音乐了。
从上面可以看到,定义客户端主要有三步:

  1. 定义ServiceConnection对象,在onServiceConnect回调中保存IBinder对象
  2. 绑定服务
  3. 使用onServiceConnect回调中保存的IBinder对象操作Service

在服务中扩展Binder这种方式适用于服务端和客户端在同一个进程中,那么如果客户端和服务端在不同进程中,那么该如何实现了?也就是通常意义上的IPC,IPC的方式有很多,比如管道、共享内存、Socket等等,但是在Android中有一种特殊的机制:Binder机制。下面首先介绍Binder机制的两种表现形式,Messenger和定义AIDL接口。下面分别就这两种方法就行介绍。
Messenger
Messenger对Binder进行了封装,适用于服务端单线程的情况,因为服务端会定义一个Handler用于顺序处理客户端发送过来的Message,在服务的onBind中返回内部的Binder。
Messenger用于发送消息,Handler用于处理消息,一般我们使用服务端作为处理消息,所以服务端需要Messenger和Handler,并且在onBind方法中返回Messenger内部的Binder,这样客户端就可以根据绑定服务后得到Messenger,可看做是服务端的Messenger,然后就可以通过它来发送消息了;那么如果服务端会在处理完客户端的消息后回复客户端,并且客户端也需要处理这个消息,那么该如何实现呢?
根据上面的分析,既然服务端需要回复客户端,也就得拿到客户端的Messenger,然后客户端需要处理消息,也需要一个Handler,所以说客户端也需要一个Messenger和一个Handler。下面我们以一个例子来详细说明,客户端向服务端发送两个整形数,服务端将和返回给客户端。
1.服务端的定义
/**

  • 使用Messenger,适合应用与服务在不同进程中
    */
    public class MessengerService extends Service {

    //Handler用于处理客户端发送来的消息,不存在线程安全问题
    private Handler mHandler = new Handler() {

     @Override
     public void handleMessage(Message msg) {
    
         switch (msg.what) {
             case 0:
                 int a = msg.arg1;
                 int b = msg.arg2;
                 int sum = a + b;
                 //得到客户端的Messenger,回复消息
                 Messenger replyTo = msg.replyTo;
                 Message message = Message.obtain();
                 message.what = 1;
                 message.arg1 = sum;
                 try {
                     replyTo.send(message);
                 } catch (RemoteException e) {
                     e.printStackTrace();
                 }
                 break;
         }
     }
    

    };
    private Messenger messenger = new Messenger(mHandler);

    public MessengerService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
    //返回Messenger内部的Binder
    return messenger.getBinder();
    }
    }
    从上面的代码可以看到,服务端主要包括三步:

  1. 定义Handler用于处理消息

  2. 根据Handler声明Messenger对象

  3. 在onBind方法中返回Messenger的Binder
    2.客户端的定义
    在定义完服务端之后,我们再来看下客户端的定义,客户端主要完成绑定服务,发送数据以及接受数据的功能。如下:
    public class MainActivity extends AppCompatActivity {
    private TextView resultShowTv;
    private Messenger messenger;
    private ServiceConnection connection = new ServiceConnection() {

     @Override
     public void onServiceConnected(ComponentName name, IBinder service) {
         //得到服务端的Messenger,发送消息
         messenger = new Messenger(service);
         Message msg = Message.obtain(handler, 0, 5, 10);
         msg.replyTo = replyTo;//将客户端的Messenger对象赋给replyTo字段
        try {
             messenger.send(msg);
         } catch (RemoteException e) {
             e.printStackTrace();
         }
     }
     @Override
     public void onServiceDisconnected(ComponentName name) {
     }   };
       @Override
         protected void onCreate(Bundle  savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_main);
     resultShowTv = (TextView) findViewById(R.id.result_show_tv);
    

    }
    //客户端中接受消息的Messenger
    private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
    switch (msg.what) {
    case 1:
    int sum = msg.arg1;
    resultShowTv.setText(String.valueOf(sum));
    break;
    }
    }
    };
    private Messenger replyTo = new Messenger(handler);、
    public void messenger(View view) {
    Intent bindService = new Intent(this, MessengerService.class);
    bindService(bindService, connection, BIND_AUTO_CREATE);
    }
    }

从上面的代码可以看到,客户端主要有三步:

  1. 编写ServiceConnection类,在onServiceConnect回调中得到服务端的Messenger,一旦得到了该对象,就发送Message对象,并且将客户端这边的Messenger带了过去
  2. 编写客户端处理消息的Handler以及Messenger
  3. 绑定服务
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值