仰天大笑出门去,我辈岂是蓬蒿人。这篇文章主要讲述Android:远程服务Service(含AIDL &
IPC讲解)相关的知识,希望能为你提供帮助。
前言
- Service作为android四大组件之一, 应用非常广泛
- 本文将介绍Service其中一种常见用法: 远程Service
如果你对Service还未了解, 建议先阅读我写的另外一篇文章:目录
Android四大组件: Service史上最全面解析
文章图片
1. 远程服务与本地服务的区别
- 远程服务与本地服务最大的区别是: 远程Service与调用者不在同一个进程里( 即远程Service是运行在另外一个进程) ; 而本地服务则是与调用者运行在同一个进程里
- 二者区别的详细区别如下图:
文章图片
2. 使用场景 多个应用程序共享同一个后台服务( 远程服务)
即一个远程Service与多个应用程序的组件( 四大组件) 进行跨进程通信
文章图片
3. 具体使用
- 为了让远程Service与多个应用程序的组件( 四大组件) 进行跨进程通信( IPC) , 需要使用AIDL
- IPC: Inter-Process Communication, 即跨进程通信
- AIDL: Android Interface Definition Language, 即Android接口定义语言; 用于让某个Service与多个应用程序组件之间进行跨进程通信, 从而可以实现多个应用程序共享同一个Service的功能。
- 在多进程通信中,
存在两个进程角色(
以最简单的为例)
:
服务器端和客户端
- 以下是两个进程角色的具体使用步骤:
服务器端( Service)
步骤1: 新建定义AIDL文件, 并声明该服务需要向客户端提供的接口
步骤2: 在Service子类中实现AIDL中定义的接口方法, 并定义生命周期的方法( onCreat、onBind()、blabla)
步骤3: 在AndroidMainfest.xml中注册服务 & 声明为远程服务
客户端( Client)
步骤1: 拷贝服务端的AIDL文件到目录下
步骤2: 使用Stub.asInterface接口获取服务器的Binder, 根据需要调用服务提供的接口方法
步骤3: 通过Intent指定服务端的服务名称和所在包, 绑定远程Service
4. 具体实例
- 实例描述: 客户端远程调用服务器端的远程Service
- 具体使用:
新建一个服务器端的工程: Service - server
先下Demo再看, 效果会更好: Github_RemoteService_Server步骤1. 新建一个AIDL文件
文章图片
步骤2. 在新建AIDL文件里定义Service需要与Activity进行通信的内容( 方法) , 并进行编译( Make Project)
// 在新建的AIDL_Service1.aidl里声明需要与Activity进行通信的方法
package scut.carson_ho.demo_service;
interface AIDL_Service1 {
void AIDL_Service();
}
//AIDL中支持以下的数据类型
//1. 基本数据类型
//2. String 和CharSequence
//3. List 和 Map ,List和Map 对象的元素必须是AIDL支持的数据类型;
//4. AIDL自动生成的接口(
需要导入-import)
//5. 实现android.os.Parcelable 接口的类(
需要导入-import)
文章图片
步骤3: 在Service子类中实现AIDL中定义的接口方法, 并定义生命周期的方法( onCreat、onBind()、blabla)
MyService.java
public class MyService extends Service {// 实例化AIDL的Stub类(Binder的子类)
AIDL_Service1.Stub mBinder =
new AIDL_Service1.Stub() {//重写接口里定义的方法
@
Override
public void AIDL_Service() throws RemoteException {
System.out.println("
客户端通过AIDL与远程后台成功通信"
);
}
};
//重写与Service生命周期的相关方法
@
Override
public void onCreate() {
super.onCreate();
System.out.println("
执行了onCreat()"
);
}@
Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("
执行了onStartCommand()"
);
return super.onStartCommand(intent, flags, startId);
}@
Override
public void onDestroy() {
super.onDestroy();
System.out.println("
执行了onDestory()"
);
}@
Nullable
@
Override
public IBinder onBind(Intent intent) {System.out.println("
执行了onBind()"
);
//在onBind()返回继承自Binder的Stub类型的Binder,
非常重要
return mBinder;
}@
Override
public boolean onUnbind(Intent intent) {
System.out.println("
执行了onUnbind()"
);
return super.onUnbind(intent);
}}
步骤4: 在AndroidMainfest.xml中注册服务 & 声明为远程服务
<
service
android:name=
"
.MyService"
android:process=
"
:remote"
//将本地服务设置成远程服务
android:exported=
"
true"
//设置可被其他进程调用
>
//该Service可以响应带有scut.carson_ho.service_server.AIDL_Service1这个action的Intent。
//此处Intent的action必须写成“服务器端包名.aidl文件名”
<
intent-filter>
<
action android:name=
"
scut.carson_ho.service_server.AIDL_Service1"
/>
<
/intent-filter>
<
/service>
【Android(远程服务Service(含AIDL & IPC讲解))】至此, 服务器端( 远程Service) 已经完成了。
4.2 客户端( Client) 新建一个客户端的工程: Service - Client
先下Demo再看, 效果会更好: Github_RemoteService_Client步骤1: 将服务端的AIDL文件所在的包复制到客户端目录下( Project/app/src/main) , 并进行编译
注: 记得要原封不动地复制! ! 什么都不要改!
文章图片
步骤2: 在主布局文件定义“绑定服务”的按钮
MainActivity.xml
<
?xml version=
"
1.0"
encoding=
"
utf-8"
?>
<
RelativeLayout 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: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=
"
scut.carson_ho.service_client.MainActivity"
>
<
Button
android:layout_centerInParent=
"
true"
android:id=
"
@
+
id/bind_service"
android:layout_width=
"
match_parent"
android:layout_height=
"
wrap_content"
android:text=
"
绑定服务"
/>
<
/RelativeLayout>
步骤3: 在MainActivity.java里
- 使用Stub.asInterface接口获取服务器的Binder;
- 通过Intent指定服务端的服务名称和所在包, 进行Service绑定;
- 根据需要调用服务提供的接口方法。
public class MainActivity extends AppCompatActivity {private Button bindService;
//定义aidl接口变量
private AIDL_Service1 mAIDL_Service;
//创建ServiceConnection的匿名类
private ServiceConnection connection =
new ServiceConnection() {//重写onServiceConnected()方法和onServiceDisconnected()方法
//在Activity与Service建立关联和解除关联的时候调用
@
Override
public void onServiceDisconnected(ComponentName name) {
}//在Activity与Service建立关联时调用
@
Override
public void onServiceConnected(ComponentName name, IBinder service) {//使用AIDLService1.Stub.asInterface()方法获取服务器端返回的IBinder对象
//将IBinder对象传换成了mAIDL_Service接口对象
mAIDL_Service =
AIDL_Service1.Stub.asInterface(service);
try {//通过该对象调用在MyAIDLService.aidl文件中定义的接口方法,从而实现跨进程通信
mAIDL_Service.AIDL_Service();
} catch (RemoteException e) {
e.printStackTrace();
}
}
};
@
Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindService =
(Button) findViewById(R.id.bind_service);
//设置绑定服务的按钮
bindService.setOnClickListener(new View.OnClickListener() {
@
Override
public void onClick(View v) {//通过Intent指定服务端的服务名称和所在包,
与远程Service进行绑定
//参数与服务器端的action要一致,即"
服务器包名.aidl接口文件名"
Intent intent =
new Intent("
scut.carson_ho.service_server.AIDL_Service1"
);
//Android5.0后无法只通过隐式Intent绑定远程Service
//需要通过setPackage()方法指定包名
intent.setPackage("
scut.carson_ho.service_server"
);
//绑定服务,传入intent和ServiceConnection对象
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
});
}}
4.3 测试结果
文章图片
从上面测试结果可以看出:
- 打印的语句分别运行在不同进程( 看语句前面的包名) ;
- 客户端调用了服务端Service的方法
4.4 Demo地址
- 客户端: Github_RemoteService_Client
- 服务端: Github_RemoteService_Server
- 本文对Android组件Service中的远程Service进行了全面介绍
- 如果你还想了解关于Service的其他知识, 请浏览以下文章:
Android四大组件: Service史上最全面解析
Android: Service生命周期最全面解析
Android: ( 本地、可通信的、前台、远程) Service使用全面介绍
Android: 远程服务Service( 含AIDL & IPC讲解)
Android多线程全面解析: IntentService用法& 源码
- 接下来会介绍继续介绍Android开发中的相关知识,
感兴趣的同学可以继续关注carson_ho的微信公众号
文章图片
文章图片
推荐阅读
- Android((本地可通信的前台远程)Service使用全面介绍)
- Android 热修复方案分析
- 6.5 为什么Android用Java不用c实现()
- 6.3 Android Framework
- Android 对电话进行监听和挂断
- Android 登录界面与首页的设计
- android studio2.0 搭建Robotium环境--apk测试没有混淆只有签名
- Android官方开发文档Training系列课程中文版(目录)
- 持续更新android studio 编译各种疑难杂症,总有你想要的~