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


前言

  • 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文件

步骤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开发:最全面、最易懂的Android屏幕适配解决方案

Android开发:Handler异步通信机制全面解析(包含Looper、Message Queue)

Android开发:顶部Tab导航栏实现(TabLayout+ViewPager+Fragment)

Android开发:底部Tab菜单栏实现(FragmentTabHost+ViewPager)

Android开发:JSON简介及最全面解析方法!

Android开发:XML简介及DOM、SAX、PULL解析对比


欢迎关注Carson_Ho的简书!

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

时间: 2024-10-14 00:23:55

Android:远程服务Service(含AIDL & IPC讲解)的相关文章

android 远程Service以及AIDL的跨进程通信

在Android中,Service是运行在主线程中的,如果在Service中处理一些耗时的操作,就会导致程序出现ANR. 但如果将本地的Service转换成一个远程的Service,就不会出现这样的问题了. 转换成远程Service非常简单,只需要在注册Service的时候将他的android:process的属性制定成 :remote就可以了. 重新运行项目,你会发现,不会出现ANR了. 为什么将MyService转换成远程Service后就不会导致程序ANR了呢?这是由于,使用了远程Serv

解读Android之Service(3)AIDL

本文翻译自android官方文档,结合自己测试,整理如下. Android Interface Definition Language(AIDL)能够让我们定义自己的编程接口,该接口可以使得客户端和service之间进行跨进程通信(interprocess communication,IPC).通常,在android中无法直接跨进程通信.因此,需要把传递的对象分解成系统可以识别的原始状态(数据),并将它们跨进程序列化marshalling.由于marshalling过程繁琐,因此android通

Android IPC机制(三)在Android Studio中使用AIDL实现跨进程方法调用

在上一篇文章Android IPC机制(二)用Messenger进行进程间通信中我们介绍了使用Messenger来进行进程间通信的方法,但是我们能发现Messenger是以串行的方式来处理客户端发来的信息,如果有大量的消息发到服务端,服务端仍然一个一个的处理再响应客户端显然是不合适的.另外,Messenger用来进程间进行数据传递但是却不能满足跨进程的方法调用,接下来我们来使用AIDL来实现跨进程方法调用,此前我们都是用Eclipse来实现的,这次我们看看在Android Studio中使用AI

android学习之remote service 的aidl详解

写在前面的话: 关于remote service中使用aidl来实现跨进程,多线程通信,我是参考了三篇文章,大概把这个弄明白了. (1)android 官方关于aidl的说明文档 docs/guide/components/aidl.html (2)Android学习笔记23服务Service之AIDL和远程服务实现进程通信以及进程间传递自定义类型参数 http://blog.csdn.net/honeybaby201314/article/details/19989455 (3) Androi

Android Bound Service(二) ----- Using AIDL

refs: http://developer.android.com/guide/components/aidl.html AIDL(Android Interface Definition Language) 就像其它接口定义语言一样.它使你可以定义服务端及客户端程序的接口,以达到跨进程沟通( IPC )的目的. 注意: 1.在多进程多线程的情况下,我们才使用 AIDL 2.单一进程时,使用实现 Binder 类的方式定义接口 3.如果只有跨进程,但不需処理多线程的情况,请使用 Messeng

Android service通过aidl 回调客户端 daemon

前端时间项目运用到AIDL,关于AIDL客户端以及AIDL服务端网络上没有一个比较完备的Demo. 而参考Demo无疑是一个比较快速的学习方法.因此,我写了一个Demo. 供大家参考,也非常欢迎大家对其中写的不好的地方进行指正. 好了,首先简述下基本功能: 在AIDL 客户端三个EditText中输入三个值,点击提交按钮,将这三个值传入到AIDL服务端进行处理. 服务端处理后会执行客户端的回调函数:在AIDL客户端界面进行刷新,并显示一个toast. 接下来看看代码结构: 需要注意的是,两个工程

Android远程服务(AIDL)实现步骤

AIDL是安卓接口定义语言的缩写 由于笔者使用的是android studio所以建立AIDL文件的位置也需要注意,要在APPNAME->main->aidl->packagename目录下,否则无法自动生成接口类文件 首先,编写我们的AIDL文件,定义接口方法,语法与JAVA略有不同 其次,我们要在建立的service类中建立实现了该AIDL文件名.stub类的子类,实现继承的方法. 在onbind方法中返回这个子类的一个实例 注册该服务,并给其一个ACTION,此ACTION就是以后

android 四大组件之Service(10) AIDL android interface definition language

Android Interface Definition Language (AIDL) 使用AIDL建立一个邻接的service需要遵循下面的步骤 1.建立.aidl文件 这个文件使用方法签名定义了语言接口 2.实现这个接口 Android SDk工具基于你的.aidl文件使用java语言生成一个接口 这个接口有一个内部抽象类,叫做Stub,它是继承Binder并且实现你AIDL接口的 你必须继承这个Stub类并且实现这些方法 3.暴露这个接口给客户端 实现一个service并且覆盖onBin

Android service binder aidl 关系

/********************************************************************************** * Android service binder aidl 关系 * 声明: * 最近一直被Android中的service.binder.aidl这三者之间的关系给搞得有点难受, * 于是就自己花了点时间,将他们之间的关系给画出来,这样思维上就清晰多了,也方便 * 和朋友沟通,减少沟通成本. * * 2016-1-10 晴 深圳