2.Android:远程服务Service(含AIDL & IPC讲解)--转载
1. Android:(本地、可通信的、前台、远程)Service使用全面介绍
=====
2.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
接下来,我将用一个具体实例来介绍远程Service的使用
4. 具体实例
- 实例描述:客户端远程调用服务器端的远程Service
- 具体使用:
4.1 服务器端(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>
至此,服务器端(远程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绑定;
- 根据需要调用服务提供的接口方法。
MainActivity.java
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地址
5. 总结
- 本文对Android组件Service中的远程Service进行了全面介绍
- 如果你还想了解关于Service的其他知识,请浏览以下文章:
Android四大组件:Service史上最全面解析
Android:Service生命周期最全面解析
Android:(本地、可通信的、前台、远程)Service使用全面介绍
Android:远程服务Service(含AIDL & IPC讲解)
Android多线程全面解析:IntentService用法&源码
前言
- Service作为Android四大组件之一,应用非常广泛
- 本文将介绍Service最基础的知识:Service的生命周期
如果你对Service还未了解,建议先阅读我写的文章:
Android四大组件:Service史上最全面解析
目录
1. Service分类
1.1 Service的类型
1.2 特点
2.具体使用解析
2.1 本地Service
这是最普通、最常用的后台服务Service。
2.1.1 使用步骤
- 步骤1:新建子类继承Service类
需重写父类的onCreate()、onStartCommand()、onDestroy()和onBind()方法
- 步骤2:构建用于启动Service的Intent对象
- 步骤3:调用startService()启动Service、调用stopService()停止服务
- 步骤4:在AndroidManifest.xml里注册Service
2.1.2 实例Demo
接下来我将用一个实例Demo进行本地Service说明
建议先下载Demo再进行阅读:(carson.ho的Github地址)Demo_for_Service
- 步骤1:新建子类继承Service类
需重写父类的onCreate()、onStartCommand()、onDestroy()和onBind()
MyService.java
public class MyService extends Service {
//启动Service之后,就可以在onCreate()或onStartCommand()方法里去执行一些具体的逻辑
//由于这里作Demo用,所以只打印一些语句
@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) {
return null;
}
}
- 步骤2:在主布局文件设置两个Button分别用于启动和停止Service
activity_main.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.demo_service.MainActivity">
<Button
android:layout_centerInParent="true"
android:id="@+id/startService"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动服务" />
<Button
android:layout_centerInParent="true"
android:layout_below="@+id/startService"
android:id="@+id/stopService"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="停止服务" />
</RelativeLayout>
- 步骤3:构建Intent对象,并调用startService()启动Service、stopService停止服务
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button startService;
private Button stopService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService = (Button) findViewById(R.id.startService);
stopService = (Button) findViewById(R.id.stopService);
startService.setOnClickListener(this);
startService.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
//点击启动Service Button
case R.id.startService:
//构建启动服务的Intent对象
Intent startIntent = new Intent(this, MyService.class);
//调用startService()方法-传入Intent对象,以此启动服务
startService(startIntent);
//点击停止Service Button
case R.id.stopService:
//构建停止服务的Intent对象
Intent stopIntent = new Intent(this, MyService.class);
//调用stopService()方法-传入Intent对象,以此停止服务
stopService(stopIntent);
}
}
}
- 步骤4:在AndroidManifest.xml里注册Service
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="scut.carson_ho.demo_service">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
//注册Service服务
<service android:name=".MyService">
</service>
</application>
</manifest>
Androidmanifest里Service的常见属性说明
属性 | 说明 | 备注 |
---|---|---|
android:name | Service的类名 | |
android:label | Service的名字 | 若不设置,默认为Service类名 |
android:icon | Service的图标 | |
android:permission | 申明此Service的权限 | 有提供了该权限的应用才能控制或连接此服务 |
android:process | 表示该服务是否在另一个进程中运行(远程服务) | 不设置默认为本地服务;remote则设置成远程服务 |
android:enabled | 系统默认启动 | true:Service 将会默认被系统启动;不设置则默认为false |
android:exported | 该服务是否能够被其他应用程序所控制或连接 | 不设置默认此项为 false |
2.1.3 测试结果
2.1.4 Demo地址
Carson.ho的Github地址:Demo_for_Service
2.2 可通信的服务Service
- 上面介绍的Service是最基础的,但只能单机使用,即无法与Activity通信
- 接下来将在上面的基础用法上,增设“与Activity通信”的功能,即使用绑定Service服务(Binder类、bindService()、onBind()、unbindService()、onUnbind())
2.2.1 实例Demo
接下来我将用一个实例Demo进行可通信的服务Service说明
建议先下载Demo再进行阅读:(carson.ho的Github地址)Demo_for_Service
- 步骤1:在新建子类继承Service类,并新建一个子类继承自Binder类、写入与Activity关联需要的方法、创建实例
public class MyService extends Service {
private MyBinder mBinder = new MyBinder();
@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()");
//返回实例
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
System.out.println("执行了onUnbind()");
return super.onUnbind(intent);
}
//新建一个子类继承自Binder类
class MyBinder extends Binder {
public void service_connect_Activity() {
System.out.println("Service关联了Activity,并在Activity执行了Service的方法");
}
}
}
- 步骤2:在主布局文件再设置两个Button分别用于绑定和解绑Service
<?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.demo_service.MainActivity">
<Button
android:layout_centerInParent="true"
android:id="@+id/startService"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动服务" />
<Button
android:layout_centerInParent="true"
android:layout_below="@+id/startService"
android:id="@+id/stopService"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="停止服务" />
<Button
android:layout_centerInParent="true"
android:layout_below="@id/stopService"
android:id="@+id/bindService"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="绑定服务" />
<Button
android:layout_centerInParent="true"
android:layout_below="@id/bindService"
android:id="@+id/unbindService"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="解绑服务"
/>
</RelativeLayout>
- 步骤3:在Activity通过调用MyBinder类中的public方法来实现Activity与Service的联系
即实现了Activity指挥Service干什么Service就去干什么的功能
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button startService;
private Button stopService;
private Button bindService;
private Button unbindService;
private MyService.MyBinder myBinder;
//创建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) {
//实例化Service的内部类myBinder
//通过向下转型得到了MyBinder的实例
myBinder = (MyService.MyBinder) service;
//在Activity调用Service类的方法
myBinder.service_connect_Activity();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
startService = (Button) findViewById(R.id.startService);
stopService = (Button) findViewById(R.id.stopService);
startService.setOnClickListener(this);
stopService.setOnClickListener(this);
bindService = (Button) findViewById(R.id.bindService);
unbindService = (Button) findViewById(R.id.unbindService);
bindService.setOnClickListener(this);
unbindService.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
//点击启动Service
case R.id.startService:
//构建启动服务的Intent对象
Intent startIntent = new Intent(this, MyService.class);
//调用startService()方法-传入Intent对象,以此启动服务
startService(startIntent);
break;
//点击停止Service
case R.id.stopService:
//构建停止服务的Intent对象
Intent stopIntent = new Intent(this, MyService.class);
//调用stopService()方法-传入Intent对象,以此停止服务
stopService(stopIntent);
break;
//点击绑定Service
case R.id.bindService:
//构建绑定服务的Intent对象
Intent bindIntent =