Android:远程服务Service(含AIDL & IPC讲解)

来源:互联网 发布:iphone电池不耐用 知乎 编辑:程序博客网 时间:2024/06/05 19:45

目录(?)[+]

  1. 前言
  2. 目录
  3. 远程服务与本地服务的区别
  4. 使用场景
  5. 具体使用
  6. 具体实例
    1. 1 服务器端Service
  7. 2 客户端Client
  8. 3 测试结果
  9. 4 Demo地址
  10. 总结
  11. 请点赞因为你们的赞同鼓励是我写作的最大动力
    1. 欢迎关注Carson_Ho的简书


前言


  • Service作为Android四大组件之一,应用非常广泛
  • 本文将介绍Service其中一种常见用法:远程Service

如果你对Service还未了解,建议先阅读我写的另外一篇文章:
Android四大组件:Service史上最全面解析


目录

目录


1. 远程服务与本地服务的区别

  • 远程服务与本地服务最大的区别是:远程Service与调用者不在同一个进程里(即远程Service是运行在另外一个进程);而本地服务则是与调用者运行在同一个进程里
  • 二者区别的详细区别如下图:

按运行地点分类


2. 使用场景

多个应用程序共享同一个后台服务(远程服务)

即一个远程Service与多个应用程序的组件(四大组件)进行跨进程通信

使用场景


3. 具体使用

  • 为了让远程Service与多个应用程序的组件(四大组件)进行跨进程通信(IPC),需要使用AIDL

    1. IPC:Inter-Process Communication,即跨进程通信
    2. 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文件

新建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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

编译

步骤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);    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

步骤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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

至此,服务器端(远程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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

步骤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);                }            });        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64

4.3 测试结果

点击绑定服务按钮

从上面测试结果可以看出:

  • 打印的语句分别运行在不同进程(看语句前面的包名);
  • 客户端调用了服务端Service的方法

客户端和服务端进行了跨进程通信

4.4 Demo地址

  • 客户端:Github_RemoteService_Client
  • 服务端:Github_RemoteService_Server

5. 总结

  • 本文对Android组件Service中的远程Service进行了全面介绍
  • 如果你还想了解关于Service的其他知识,请浏览以下文章:

    Android四大组件:Service史上最全面解析
    Android:Service生命周期最全面解析
    Android:(本地、可通信的、前台、远程)Service使用全面介绍
    Android:远程服务Service(含AIDL & IPC讲解)
    Android多线程全面解析:IntentService用法&源码

  • 接下来会介绍继续介绍Android开发中的相关知识,有兴趣可以继续关注Carson_Ho的安卓开发笔记


请点赞!因为你们的赞同/鼓励是我写作的最大动力!

相关文章阅读
Android开发:最全面、最易懂的Android屏幕适配解决方案
Android开发:Handler异步通信机制全面解析(包含Looper、Message Queue)
Android开发:顶部Tab导航栏实现(TabLayout+ViewPager+Fragment)
Android开发:底部Tab菜单栏实现(FragmentTabHost+ViewPager)
Android开发:JSON简介及最全面解析方法!
Android开发:XML简介及DOM、SAX、PULL解析对比


欢迎关注Carson_Ho的简书!

不定期分享关于安卓开发的干货,追求短、平、快,但却不缺深度

0 0
原创粉丝点击