08 Service通信

一、应用内通信

1、启动Service并传递数据

启动一个Service并且向该Service传递数据:

1
2
3
Intent intent = new Intent(this, MyService.class);
intent.putExtra("data", mEditText.getText().toString().trim());
startService(intent);

MyService接收数据:

1
2
3
4
5
6
7
private String data = "MyService default info";
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
data = intent.getStringExtra("data");
return super.onStartCommand(intent, flags, startId);
}

2、绑定Service进行通信——>

与被绑定的Service进行通信,首先自定义一个Binder的实现类,拥有setData(String data)方法,并在onBind方法中返回自定义类的对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class MyService extends Service {
private String data = "MyService default info";
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
public class MyBinder extends Binder {
public void setData(String data) {
MyService.this.data = data;
}
}
...
}

在ServiceConnection实现类中onServiceConnected方法里获取服务绑定成功时返回的对象

1
2
3
4
5
6
7
8
9
10
11
public class MainActivity extends AppCompatActivity implements View.OnClickListener, ServiceConnection {
private MyService.MyBinder mMyBinder;
...
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mMyBinder = (MyService.MyBinder) service;
}
}

然后MainActivity就可以实时的想MyService同步数据了:

1
2
if (mMyBinder != null)
mMyBinder.setData(mEditText.getText().toString().trim());

输出日志

1
2
3
4
5
6
7
8
9
I/System.out: MyService onCreate
I/System.out: MyService default info
I/System.out: MyService default info
I/System.out: MyService default info
I/System.out: MyService default info
I/System.out: MainActivity say something
I/System.out: MainActivity say something
I/System.out: MainActivity say something
I/System.out: MyService onDestroy

3、绑定Service进行通信<——

侦听被绑定的Service的内部状态,需要借助回调接口。首先定义回调接口并设置set(callBack)方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyService extends Service {
private CallBack mCallBack;
public void setCallBack(CallBack callBack) {
mCallBack = callBack;
}
public static interface CallBack {
public void onDataChange(String data);
}
...
}

自定义类MyBinder中增加一个方法,返回当前Service的对象,以便于外部客户端调用set(callBack)方法

1
2
3
4
5
6
7
8
public class MyBinder extends Binder {
...
public MyService getService() {
return MyService.this;
}
}

在Service中将状态信息通过回调接口通知外界

1
2
3
i++;
if (mCallBack != null)
mCallBack.onDataChange(i + " " + data);

ServiceConnection的实现类(此处为MainActivity)在onServiceConnected方法中获取Service对象,并将自定义的回调接口告知Service:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mMyBinder = (MyService.MyBinder) service;
mMyBinder.getService().setCallBack(new MyService.CallBack() {
@Override
public void onDataChange(String data) {
Message msg = new Message();
Bundle bundle = new Bundle();
bundle.putString("data", data);
msg.setData(bundle);
mHandler.sendMessage(msg);
}
});
}

借助Handler,将数据同步到TextView上:

1
2
3
4
5
6
7
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
mTextView.setText(msg.getData().getString("data"));
}
};

二、跨应用通信——AIDL

1、跨应用启动Service

从Android5.0以后,只能通过显示Intent来启动服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.xianxiaotao.firstapp;
public class MainActivity extends AppCompatActivity {
private Intent mIntent;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
mIntent = new Intent();
mIntent.setComponent(new ComponentName("com.xianxiaotao.secondapp", "com.xianxiaotao.secondapp.AppService"));
startService(mIntent)
}
@Override
protected void onDestroy() {
super.onDestroy();
stopService(mIntent);
}
}

2、跨应用绑定Service

新建AIDL文件:New -> AIDL -> AIDL File -> IAppServiceRemoteBinder.aidl

1
2
3
4
5
package com.xianxiaotao.secondapp;
interface IAppServiceRemoteBinder {
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString);
}

在Service里实现该接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.xianxiaotao.secondapp;
public class AppService extends Service {
...
@Override
public IBinder onBind(Intent intent) {
return new IAppServiceRemoteBinder.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) {
// TODO
}
};
}
}

在第一个应用中绑定服务和解除绑定服务:

1
2
bindService(mIntent, this, Context.BIND_AUTO_CREATE);
unbindService(this);

3、跨应用绑定Service并通信

在IAppServiceRemoteBinder接口中新增setData方法

1
2
3
4
interface IAppServiceRemoteBinder {
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString);
void setData(String data);
}

其子类需要实现该方法

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public IBinder onBind(Intent intent) {
return new IAppServiceRemoteBinder.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) {
// TODO
}
@Override
public void setData(String data) throws RemoteException {
AppService.this.data = data;
}
};
}

在第一个应用里创同样的IAppServiceRemoteBinder.aidl文件,注意包名也要一致。

  • firstApp -> New -> Folder -> AIDL Folder
  • aidl -> New -> Package -> com.xianxiaotao.secondapp -> OK
  • 在该文件夹里创建同样的IAppServiceRemoteBinder.aidl文件,测试时可以直接复制粘贴。
    上述操作执行完毕后,该应用绑定secondapp的AppService时,可以获取到IBinder的实例了。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    private IAppServiceRemoteBinder binder = null;
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
    // 此处不能用强制类型转换,虽然类名相同,但两个类在内存中地址不一样
    binder = IAppServiceRemoteBinder.Stub.asInterface(service);
    }
    ...
    if (binder != null) {
    try {
    binder.setData(mEditText.getText().toString().trim());
    } catch (RemoteException e) {
    e.printStackTrace();
    }
    }