一、基本用法(使用bind的方式注册Service)
(1)新建一个继承自Service的类MyService,然后在AndroidManifest.xml里注册这个Service.
(2)Activity里面使用bindService方式启动MyService,也就是绑定了MyService.
(3)新建一个继承自Binder的类MyBinder
(4)在MyService里实例化一个MyBinder对象mBinder,并在onBind回调方法里边返回mBinder对象
(5)第2步bindService方法需要一个ServiceConnection类型的参数,在ServiceConnection里可以取到一个IBinder对象,就是第4步onBinder返回的mBinder对象(也就是在Activity里面拿到了Service里面的mBinder对象)
(6)在Activity里面拿到mBinder之后就可以调用这个binder里面的方法了(也就是可以给Service发消息了),需要什么方法在MyBinder类里面定义实现就行了。如果需要Service给Activity发消息的话,通过这个binder注册一个自定义回调即可。
二、代码实现
Service
public class MyService extends Service {
private static final String TAG="wcy";
//实例化一个MyBinder对象
private MyBinder myBinder=new MyBinder(this);
@Nullable
@Override
public IBinder onBind(Intent intent) {
return myBinder;
}
public void serviceMothod(String str){
Log.i(TAG,"receive msg from activity:"+str);
}
}
Service也是四大组件之一,所以创建一个Service类也需要在功能清单文件中注册。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.wcystart.wcystart">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".MyService"
android:enabled="true"
android:exported="true">
</service>
</application>
</manifest>
android:enabled="true" 代表是否能被其他应用隐式调用,其默认值是由service中有无intent-filter决定的,如果有intent-filter,默认值为true,否则为false。为false的情况下,即使有intent-filter匹配,也无法打开,即无法被其他应用隐式调用。能被跨进程使用。
android:exported="true" 代表是否能被其他的应用隐式调用
Binder
public class MyBinder extends Binder {
private static final String TAG = "wcy";
private MyService mService;
onTestListener mOnTestListener;
public MyBinder(MyService service){
this.mService=service;
}
public void testMothod(String str){
//Activity 通过Binder来调用Service的方法将消息传给Activity
mService.serviceMothod(str);
mOnTestListener.onTest("hi,activity");
}
//MyBinder里边提供一个注册回调的方法
public void setOnTestListener(onTestListener onTestListener) {
this.mOnTestListener = onTestListener;
}
//自定义一个回调接口
public interface onTestListener {
void onTest(String str);
}
}
Activity
public class FirstActivity extends Activity implements View.OnClickListener {
private static String TAG = "FirstActivity";
private Button mBtnMain;
private MyBinder myBinder;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder = (MyBinder) service;
myBinder.setOnTestListener(new MyBinder.onTestListener() {
@Override
public void onTest(String str) {
Log.i(TAG, "receive msg from service:" + str);
}
});
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBtnMain = findViewById(R.id.btn_main);
//跳转到Service
Intent intent=new Intent(this,MyService.class);
bindService(intent,mConnection,BIND_AUTO_CREATE);
mBtnMain.setOnClickListener(this);
}
@Override
public void onClick(View v) {
myBinder.testMothod("hi,service.");
}
}
bindService(intent,mConnection,BIND_AUTO_CREATE);
第一个bindService()的参数是一个明确指定了要绑定的service的Intent.
第二个参数是ServiceConnection对象.
第三个参数是一个标志,它表明绑定中的操作.它一般应是BIND_AUTO_CREATE,这样就会在service不存在时创建一个.其它可选的值是BIND_DEBUG_UNBIND和BIND_NOT_FOREGROUND,不想指定时设为0即可.。//当bindService最后一个参数为Context.BIND_AUTO_CREATE时会和service建立连接,会在连接建立之后调用onServiceConnected方法,当bindService最后一个参数为Context.BIND_DEBUG_UNBIND时会断开和service的链接,会在断开连接后调用onServiceDisconnected()方法。
三、为了防止内存泄漏,需要在Activity销毁的时候解绑Service
@Override
protected void onDestroy() {
super.onDestroy();
//当Activity销毁的时候解服务
if(mConnection!=null){
unbindService(mConnection);
mConnection=null;
}
}
总结
代码很简单,首先Activity绑定Service得到一个MyBinder实例并注册MyBinder里面的OnTestListener回调监听,然后点击按钮的时候调用MyBinder里面的testMethod(String)方法将消息发出去,MyBinder持有一个MyService的实例,testMethod(String)里面调用MyService里面的方法就可以把Activity的消息传给Service了,然后testMethod(String)里面回调mListener.onTest(String)将Service的消息发给Activity。
MyBinder定义在MyService里面作为内部类也是很常见的写法,这里为了方便后面的讲解写成了普通类的形式。
至此就实现了同进程下Activity与Service的双向通信,运行代码,点击按钮后log如下:
wcy: receive msg from activity:hi,service.
FirstActivity: receive msg from service:hi,activity
通过打印日志可以看到,Activity与Service之间是通过一个Binder对象来通信的。