知识点列表
1.生命周期
2.启动方式
3.跨进程通信
4.双向通信
一 生命周期
Service的生命周期跟启动方式有关,启动方式有俩种,startService和bindService,对应生命周期如下
![](https://img.haomeiwen.com/i3481369/f4eb06035665ebc3.png)
二 启动方式
startService()
通过startService启动后,service会一直无限期运行下去,只有外部调用了stopService()或stopSelf()方法时,该Service才会停止运行并销毁。
调用startService的时候
第一次调用
构造方法——onCreate()——onStartCommand()
当第二次调用
直接调用onStartCommand()
当调用stopService()的时候
直接调用onDestory()
bindService()
bindService启动的服务和调用者之间是典型的client-server模式。调用者是client,service则是server端。service只有一个,但绑定到service上面的client可以有一个或很多个,这里所提到的client指的是组件,比如某个Activity。
bindService启动服务的生命周期与其绑定的client息息相关,client也可以明确调用Context的unbindService()方法与Service解除绑定。当所有的client与service解除绑定的时候,才会调用onUnbind,然后 Service会自行销毁。
startService和bindService区别
client可以通过IBinder接口获取Service实例,从而实现在client端直接调用Service中的方法以实现灵活交互,这在通过startService方法启动中是无法实现的。
三 跨进程通信
Service跨进程通信,设计到三个东西,Service,Client,AIDL,client通过bindService的方式可以和Service进行AIDL跨进程通信,在Service中定义好AIDL的Stub实现类,通过在Service的onBind回调中返回IBinder对象,client绑定时,获取到该IBinder对象,即可进行传递参数
AIDL文件
在android studio中,app/src/main,下面新建一个aidl文件夹,再在该aidl文件夹下按照包名再新建一个文件夹,这里面用来写aidl文件
interface IMyAidlInterface {
int calculate(int x, int y);
}
建好之后,build一下,在build/generated/aidl_source_output_dir/debug/out/包名/,路径下,会生成真正用来通讯的文件,这其实就是AIDL的实际通讯过程,android为了简化,只需要我们定义好AIDL接口,自动给我们生成该类,实际上可以直接编写该类就可以进行通讯,里面包含一个内部静态类Stub,我们需要再定义个实现类继承该Stub,如下
public class MyAidlServiceImpl extends IMyAidlInterface.Stub {
private final String TAG = "MyAidlServiceImpl";
public MyAidlServiceImpl() {
}
@Override
public int calculate(int x, int y) throws RemoteException {
Log.d(TAG, x + y + "");
return x + y;
}
}
Service
Service里面用来通过onBind方法来传递该AIDL,实现通信
public class MyService extends Service {
private MyAidlServiceImpl service;
@Override
public void onCreate() {
super.onCreate();
service = new MyAidlServiceImpl();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return service;
}
}
Client
客户端需要通过bindService来获取到Service的IMyAidlInterface,即可调用对应方法实现通信
public class MainActivity extends Activity {
private final String TAG = "MainActivityInformation";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.method_one).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
connect();
if (aidlInterface == null) {
return;
}
try {
Toast.makeText(MainActivity.this, "计算成功: " + aidlInterface.calculate(10, 20), Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
private IMyAidlInterface aidlInterface;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
aidlInterface = IMyAidlInterface.Stub.asInterface(service);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "连接成功", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onServiceDisconnected(ComponentName name) {
aidlInterface = null;
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "连接断开", Toast.LENGTH_SHORT).show();
}
});
}
};
}
四 双向通信
单向通信指的是,数据只能从client流向Service,而双向通信则是指数据可以在client和Service之间互相流通,双向通信通过inout和回调监听可以实现双向通信
提供一个用来传递的序列化的类
public class Person implements Parcelable {
public String name;
public int age;
public String describe;
public Person(){
}
...
@Override
public String toString() {
return "我叫" + name + ",今年" + age + "岁," + describe;
}
...
}
然后定义对应的aidl文件
package visual.share.aidlservice;
parcelable Person;
一个用来监听和回调数据的AIDL
interface IMyAidlInterface {
void inOutData(String name, int age, String describe, inout Person data);
void registerCallBack(PersonResultListen listen);
void unregisterCallBack(PersonResultListen listen);
void callBackData();
}
一个回调监听
interface PersonResultListen {
void result(inout Person person);
}
然后来实现IMyAidlInterface的实现类,如下
public class MyAidlServiceImpl extends IMyAidlInterface.Stub {
private RemoteCallbackList<PersonResultListen> remoteCallbackList = new RemoteCallbackList<>();
@Override
public void inOutData(String name, int age, String describe, Person data) throws RemoteException {
data.name = name;
data.age = age;
data.describe = describe;
}
@Override
public void registerCallBack(PersonResultListen listen) throws RemoteException {
if (listen != null) {
remoteCallbackList.register(listen);
}
}
@Override
public void unregisterCallBack(PersonResultListen listen) throws RemoteException {
if (listen != null){
remoteCallbackList.unregister(listen);
};
}
@Override
public void callBackData() throws RemoteException {
synchronized (remoteCallbackList){
int count = remoteCallbackList.beginBroadcast();
if (count > 0){
Person person = new Person();
person.name = "监听回调";
person.age = 20;
person.describe = "监听回调的描述";
for (int i = 0; i < count; i++) {
remoteCallbackList.getBroadcastItem(i).result(person);
}
}
remoteCallbackList.finishBroadcast();
}
}
}
这里我们的inOutData方法,里面用到了inout标识,用来实现双向通信,callBackData方法用来实现接口回调,而registerCallBack和unregisterCallBack则是用来注册和取消注册这个监听回调,需要注意的时候,这里使用的是RemoteCallbackList来存储回调队列,这个类专门用来处理跨进程通信的回调
定义一个Service,用来获取我们这个AIDL实现类
public class MyService extends Service {
private MyAidlServiceImpl service;
@Override
public void onCreate() {
super.onCreate();
service = new MyAidlServiceImpl();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return service;
}
}
然后在应用中就可以直接使用
public class MainActivity extends Activity {
private final String TAG = "MainActivity";
private Intent intent;
@SuppressLint("MissingInflatedId")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent(MainActivity.this, MyService.class);
bindService();
findViewById(R.id.inout_data).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (aidlInterface != null){
try {
Person person = new Person();
aidlInterface.inOutData("小明", 25, "长得很帅",person);
Toast.makeText(MainActivity.this, person.toString(), Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
}
});
findViewById(R.id.callback_data).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (aidlInterface != null){
try {
aidlInterface.callBackData();
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
}
});
}
private void bindService(){
boolean flag = bindService(intent, connection,BIND_AUTO_CREATE);
Log.d(TAG, "connect status" + flag);
}
private IMyAidlInterface aidlInterface;
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
aidlInterface = IMyAidlInterface.Stub.asInterface(service);
try {
aidlInterface.asBinder().linkToDeath(deathRecipient, 0);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
try {
aidlInterface.registerCallBack(personResultListen);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
aidlInterface = null;
}
};
private PersonResultListen.Stub personResultListen = new PersonResultListen.Stub() {
@Override
public void result(Person person) throws RemoteException {
Toast.makeText(MainActivity.this, person.toString(), Toast.LENGTH_SHORT).show();
}
};
private IBinder.DeathRecipient deathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
try {
aidlInterface.unregisterCallBack(personResultListen);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
if (aidlInterface != null){
aidlInterface.asBinder().unlinkToDeath(deathRecipient, 0);
}
bindService();
}
};
}
打开应用后就绑定服务,这里我们添加监听是在绑定成功之后添加,并且使用了死亡代理,Binder.DeathRecipient,当和服务断开的时候,再取消注册的监听,布局如下
<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/inout_data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"
android:text="获取inout数据" />
<Button
android:id="@+id/callback_data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="10dp"
android:text="获取回调数据" />
</LinearLayout>
这里提供了俩个按钮,点击后,分别获得通过inout处理后的数据,和通过回调返回的数据,实现了双向通信。
最后测试demo结构如下
![](https://img.haomeiwen.com/i3481369/c57611c0cb8dd97b.png)
IntentService
Service因为是运行在主线程,不能处理耗时任务,否则会可能会出现ANR问题,IntentService 是继承于 Service 并处理异步请求的一个类,在 IntentService 内有一个子线程来处理耗时操作,启动 IntentService 的方式和启动传统 Service 一样,同时,当任务执行完后,IntentService 会自动停止,而不需要我们去手动控制。
踩坑
1.binderService和unbinderService需要用使用同一个ServiceConnection
如果不使用同一个,当调用unbindService时,会提示Service not registered错误
2.onServiceDisconnected不回调
当bindService后,如果Client和Service连接成功,会调用ServiceConnection的onServiceConnected方法,但是调用unbindService解除绑定时,不会调用onServiceDisconnected方法,这是因为当Client和Service连接后,只有到Service因为异常原因崩溃,才会调用onServiceDisconnected方法
网友评论