客户端通过调用bindService方法能够绑定服务,然后Android系统会调用服务的onBind回调方法,这个方法会返回一个跟服务端交互的IBinder对象。这个绑定是异步的,bindService方法立即返回,并且不给客户端返回IBinder对象。要接受IBinder对象,客户端必须创建一个ServiceConnection类的实例,并且把这个实例传递给bindService方法。
注意:只有Activity、Service和内容提供器(content provider)能够绑定服务,广播接收器是不能绑定服务的。
通过绑定服务来实现功能有以下几个步骤:
实现一个ServiceConnection接口,并重写里面的onServiceConnected和onServiceDisconnected两个方法,其中,前者是在服务已经绑定成功后回调的方法,后者是在服务发生异常终止时调用的方法。
在客户端,通过bindService方法来异步地绑定一个服务对象,如果绑定成功,则会回调ServiceConnection接口方法中的onServiceConnected方法,并得到一个IBinder对象。
服务端通过创建一个*.aidl文件来定义一个可以被客户端调用的业务接口,同时,服务端还需要提供一个业务接口的实现类,并实现*.aidl中定义的所有方法,通常让这个实现类去继承Stub类。
注意:创建aidl文件时有几个注意点:
(1)定义的方法前面不能有修饰符,类似于接口的写法。
(2)支持的类型有:8大基本数据类型,CharSequence,String,List<String>,Map,以及自定义类型。
自定义类型需要做到以下几点:
实现Parcelable接口。
定义一个aidl文件来声明该类型。
如果要在其他的aidl文件中使用,则必须要使用import来引用。
通过Service组件来暴露业务接口。
通过Service的onBind方法来返回被绑定的业务对象。
客户端如果绑定成功,就可以像调用自己的方法一样去调用远程的业务对象方法。
为了便于理解,可以看一看下面的这个项目,项目名为ServiceINS。
先来看看项目的构成:
MainActivity:
package com.example.serviceins;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.View;
import android.widget.Toast;
public class MainActivity extends Activity {
private ICat cat;
private boolean isBound = false;// 用于判断是否绑定
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
// 绑定服务的连接回调接口
private ServiceConnection conn = new ServiceConnection() {
// 已经绑定完成时调用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 绑定成功后回调的方法
cat = ICat.Stub.asInterface(service);
isBound = true;
Toast.makeText(MainActivity.this, "绑定成功", Toast.LENGTH_SHORT)
.show();
}
// 服务发生异常终止时调用的方法
@Override
public void onServiceDisconnected(ComponentName name) {
isBound = false;
}
};
// 绑定服务
public void boundClick(View view) {
Intent intent = new Intent(this, MyBoundService.class);
// 这个绑定的步骤是异步的,绑定成功后会回调onServiceConnected方法
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
// 解除绑定
public void unBoundClick(View view) {
if (isBound) {
unbindService(conn);
Toast.makeText(MainActivity.this, "解除绑定成功", Toast.LENGTH_SHORT)
.show();
}
}
// 通过IPC调用业务方法
public void callClick(View view) {
if (cat == null) {
return;
}
try {
cat.setName("黑猫警长");
Toast.makeText(this,
cat.desc() + "\n" + cat.getPerson().toString(),
Toast.LENGTH_LONG).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="boundClick"
android:text="绑定一个服务" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="unBoundClick"
android:text="解除绑定服务" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="callClick"
android:text="通过IPC调用业务方法" />
</LinearLayout>
ICat.aidl:
package com.example.serviceins;
import com.example.serviceins.Person;
interface ICat {
void setName(String name);
String desc();
}
ICatImpl:
package com.example.serviceins;
import android.os.RemoteException;
import com.example.serviceins.ICat.Stub;
/*
* 业务接口的具体实现类
*/
public class CatImpl extends Stub {
private String name;
@Override
public void setName(String name) throws RemoteException {
this.name = name;
}
@Override
public String desc() throws RemoteException {
return "hello! my name is " + name + "," + "I am a police.";
}
}
MyBoundService:
package com.example.serviceins;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class MyBoundService extends Service {
public MyBoundService() {
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public IBinder onBind(Intent intent) {
return new CatImpl();
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
super.onDestroy();
}
}