1)前言
本文是接着上篇没有介绍完的Android服务Service写的,主要是想对Bound式服务做一个总结,从学Android到现在,我很少用到Bound式服务,倒是Started式服务用得不少(可能太菜),借着这个机会,结合官方文档案例对Bound式服务做一个全面的了解。
2)基本用法
一个绑定服务,就是一个实现了类Service,并允许其它应用程序与其绑定及与之交互的的组件。提供一个绑定服务,你必须实现onBind()方法,这个方法返回一个IBinder对象,这个对象就是定义用来客户端与服务交互的接口。
客户端通过bindService()方法绑定服务。另外,客户端还必须提供一个ServiceConnection的实现对象,用以监控与服务Service间的连接情况。bindService()无返回值,但系统在客户端与服务端连接之间,会调用在ServiceConnect对象中的onServiceConnected()方法,并传递一个客户端与服务端可以交互的IBinder接口。
多个客户端同时连接Service时,系统只在第一个客户端连接时调用你的onBind()方法并返回一个IBinder对象,系统在其他客户端进行连接时返回相同的IBinder对象,而不再去调用onBind().
当最后一个客户端调用与服务解除绑定时,系统将销毁服务,除非这个服务启动时,也调用了startService()方法.
创建绑定服务,必须提供IBinder接口,有三种方式定义这个接口:
- 1) 实现Binder类
如果这个service只是为当前应用服务,并且运行在相同的进程里,创建的接口必须继承Binder类,并且在onBind()方法中返回。客户可以通过它得到Binder对象,通过这个对象可以直接访问共有函数。
当service仅仅为自己的应用服务,这是首选技术。
- 2) 使用Messenger
如果需要接口在不同的进程间使用,可以用Messenger 为service类创建接口。用这种方式, service对处理不同的Message 对象定义了一个Handler. 这个Handler是Messenger的基础,可以与客户分享IBinder,允许客户用message发送命令到service上。补充点,客户端可以自定义Messenger,因此service可以发送消息回来。
这是在进程间通信最简单的方式。因为Messenger队列所有的请求发生在一个线程上,因此不需要考虑service的线程安全。
- 3) 使用AIDL
AIDL (Android Interface Definition Language) 可以把对象分解成系统能够识别的单元,已达到在进程间通信的能力。在前面的技术中,使用的messenger,实际上是以AIDL作为基础的结构。如上所述,Messenger在一个线程中创建了所有客户请求的一个队列。如果你想service能够同时处理多个请求,那么就可以直接用AIDL. 在这种案例中,service 必须要有处理多线程的能力,并且是线程安全的。
要想直接使用AIDL,必须创建定义程序的接口文件,后缀是.aidl。Android SDK工具可以通过这个文件生成一个实现了这个接口和处理IPC的抽象类,自定义的service需要继承自这个抽象类。
这种方式暂且不讨论
下面分别看下具体三种使用方法
3)实现Binder类
1、 在你的服务类中,创建一个满足下面条件的Binder实现类:
包含一个public方法,以便客户端可以调用
在一个public方法中返回当前服务实例给客户端使用
2、 在onBind()方法中,返回Binder对象实例
3、 在客户端,从onServiceConnected()回调方法接收Binder对象,并调用绑定服务中提供的方法。
下面来看下代码
//服务端
public class BoundTest extends Service {
private static final String TAG = "chen";
private IBinder iBinder = new LocalBinder();
private Random mGenerator = new Random();
public class LocalBinder extends Binder{
public BoundTest getService(){
return BoundTest.this;
}
}
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate");
}
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind");
return iBinder;
}
@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "onUnbind");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestory");
}
}
我们可以看见在服务端LocalBinder是一个内部类,其继承了Binder,里面有个公共方法,返回该服务的实例。并且有一个getRandomNumber()测试方法,供客户端调用。
//客户端
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button btn_bound;
private Button btn_unbound;
private Button btn_getrandom;
private BoundTest mService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_bound = (Button) findViewById(R.id.btn_bound);
btn_unbound = (Button) findViewById(R.id.btn_unbound);
btn_getrandom = (Button) findViewById(R.id.btn_getrandom);
btn_bound.setOnClickListener(this);
btn_unbound.setOnClickListener(this);
btn_getrandom.setOnClickListener(this);
}
@Override
public void onClick(View view) {
Intent intent = null;
switch (view.getId()){
case R.id.btn_bound:
intent = new Intent(MainActivity.this, BoundTest.class);
//绑定服务
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
break;
case R.id.btn_unbound:
intent = new Intent(MainActivity.this, BoundTest.class);
//解绑服务
unbindService(mConnection);
break;
case R.id.btn_getrandom:
int number = mService.getRandomNumber();
btn_getrandom.setText("获取随机数"+number);
break;
}
}
private ServiceConnection mConnection = new ServiceConnection() {
//绑定成功回调
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
BoundTest.LocalBinder binder = (BoundTest.LocalBinder) service;
mService = binder.getService(); //获取Binder对外提供的接口
}
//绑定失败回调
@Override
public void onServiceDisconnected(ComponentName arg0) {
}
};
}
//布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.chen.demo.MainActivity">
<Button
android:id="@+id/btn_bound"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="绑定"
/>
<Button
android:layout_marginTop="20dp"
android:id="@+id/btn_unbound"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="解绑"
/>
<Button
android:layout_marginTop="20dp"
android:id="@+id/btn_getrandom"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="获取随机数"
/>
</LinearLayout>
我们在客户端通过bindService()绑定服务,通过unbindService()解绑服务,其中bindService()需要三个参数意思分别是:
第一个变量是通过Intent指定要绑定的service.
第二个参数是 ServiceConnection 对象.
第三个参数是设置绑定的选项。通常是BIND_AUTO_CREATE,当service不在运行时,会自动创建。其他值有BIND_DEBUG_UNBIND 和BIND_NOT_FOREGROUND, 或者是0(没有任何意义).
而unbindService(),需要一个参数ServiceConnection
我们看下运行结果:
结果是最后一个Button的Text后面的数字
4)使用Messenger
如果service需要与远程的进程通讯,可以用Messenger为service提供一个接口。这种技术可以处理进程间的通讯。
下面是使用messenger的简介:
1)service 要实现Handler,它可以收到每一个client调用的回调。
2)Handler用于创建Messenger对象。 (which is a reference to the Handler).
3)Messenger创建一个IBinder,client调用onBind()时,IBinder要返回给client的
4)Clients 通过IBinder实例化Messenger(that references the service’s Handler),Messenger为了client发送Message对象到service。
5)service 通过Handler收到每一个Message, 在 handleMessage() 方法明确的处理.
利用这种方式,service中没有方法可一个被Client调用。client通过传递消息(messages)到service的Handler中。
我们简单看下服务端代码
//服务端
public class MessengerService extends Service {
private static final String TAG = "chen";
public static final int MSG_SAY_HELLO = 1;
public class IncomingHandler extends Handler{
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SAY_HELLO:
Toast.makeText(getApplicationContext(), "hello!", Toast.LENGTH_SHORT).show();
break;
default:
super.handleMessage(msg);
}
}
}
final Messenger mMessenger = new Messenger(new IncomingHandler());
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate");
}
@Override
public IBinder onBind(Intent intent) {
Log.i(TAG, "onBind");
return mMessenger.getBinder();
}
@Override
public boolean onUnbind(Intent intent) {
Log.i(TAG, "onUnbind");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i(TAG, "onDestory");
}
}
注意:Handler 的handleMessage()方法收到Message,并且根据Message的what变量 确定需要做什么。
Client的需要实现的是,基于返回的IBinder创建Messenger对象,并且通过send()发送Message给service的Handler。
//客户端
public class MessengerActivity extends AppCompatActivity implements View.OnClickListener{
private Button btn_bound;
private Button btn_unbound;
private Button btn_getrandom;
Messenger mService = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_messenger);
btn_bound = (Button) findViewById(R.id.btn_bound);
btn_unbound = (Button) findViewById(R.id.btn_unbound);
btn_getrandom = (Button) findViewById(R.id.btn_getrandom);
btn_bound.setOnClickListener(this);
btn_unbound.setOnClickListener(this);
btn_getrandom.setOnClickListener(this);
}
@Override
public void onClick(View view) {
Intent intent = null;
switch (view.getId()){
case R.id.btn_bound:
intent = new Intent(MessengerActivity.this, MessengerService.class);
//绑定服务
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
break;
case R.id.btn_unbound:
//解绑服务
unbindService(mConnection);
break;
case R.id.btn_getrandom:
Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);
try {
mService.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(mConnection);
}
private ServiceConnection mConnection = new ServiceConnection() {
//绑定成功回调
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
mService = new Messenger(service);
}
//绑定失败回调
@Override
public void onServiceDisconnected(ComponentName arg0) {
}
};
}
注意: 这个例子没有体现service是如何响应client。如果想service响应client,需要在client里面创建一个Messenger。当client收到onServiceConnected()回调,就会发送Message到service,send()方法的Message变量replyTo包括客户端的Messenger,从而实现双向通讯。
看下运行结果:
这个Toast是服务端打印的结果。
5)生命周期管理
当service没有被任何的client绑定,android系统会杀死它(除非中途被其他的组件调用了onStartCommand())。按照这种原理, 绑定service是不需要管理它的生命周期的-android系统会根据绑定原则自动管理service。
然而,如果选择onStartCommand()方法实现,就必须明确的停止service,因为服务当前状态被认为是started。在这种案例下,service一直运行直到调用stopSelf()或者其他的组件调用stopService()方法,不管他绑定任何clients.这里的意思是说:当一个绑定service通过onStartCommand()启动,需要stopSelf()和stopService()方法来停止它,即使是中间绑定其他的客户端。
补充点,如果service已经启动并且接受了client的绑定,那么当系统调用onUnbind()方法时,如果想client下次绑定service的时候调用onRebind(),可以选择返回true,(而不是重新调用onBind()). onRebind() 返回 void, 但是client在onServiceConnected()还是接受IBinder. 下面的图阐明了上面的逻辑。
6)最后
服务基本内容也就这么多,还有一个AIDL没有介绍,下次准备结合Android Studio详细介绍下
7) Ref
1 )Android 官方文档
2 )http://blog.163.com/cazwxy_12/blog/static/898763720122106483898/
3 )http://blog.csdn.net/luhuajcdd/article/details/8756541