Android之探究Service

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36391075/article/details/82955002

虽然Service作为Android四大组件之一,但是我真的在项目中很少用到它,最近写个人项目的时候,需要写一个小的音乐播放器在项目中,就用到了Service,所以现在来总结总结它。

什么是Service?

还是看官网的解释:

两不是:

A Service is not a separate process. The Service object itself does not imply it is running in its own process; unless otherwise specified, it runs in the same process as the application it is part of.

A Service is not a thread. It is not a means itself to do work off of the main thread (to avoid Application Not Responding errors).

Service不是一个单独的进程。Service对象本身并不意味着它运行在自己的进程;除非另有特别的指定,它将和应用程序运行的同一个进程中。

Service不是一个线程。它本身并不是一种在主线程之外工作的方法(例如,避免ANR错误)

两特点:

A facility for the application to tell the system about something it wants to be doing in the background (even when the user is not directly interacting with the application). This corresponds to calls to Context.startService(), which ask the system to schedule work for the service, to be run until the service or someone else explicitly stop it.

A facility for an application to expose some of its functionality to other applications. This corresponds to calls to Context.bindService(), which allows a long-standing connection to be made to the service in order to interact with it.

一种应用程序的工具,去告诉系统它想要在后台执行的操作(即使用户没有执行跟应用程序交互)。对应调用Context.startService()运行,让系统去为service做调度,直到service或其他明确让它停止。

一种应用程序的工具,将某些功能暴露给其他应用程序。对应调用Context.bindService(),这允许和Service建立长期连接,以便和Service进行交互。

那Service到底是什么呢?

扫描二维码关注公众号,回复: 3919318 查看本文章

A Service is an application component representing either an application’s desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use.

Service是一种应用程序组件,表示应用程序在不与用户交互的情况下执行较长时间的操作,或者为其他应用程序提供一些要使用的功能。

Service只是从逻辑上表示一个用来执行“longer-running”的“后台”任务或者功能的“application component”

为什么要强调“longer-running”的“component”?这里是和Activity这种活跃周期相对短暂的component对比而言。一旦用户切换到其他应用,当前Activity就必须pause,stop甚至被destroy,不能再后台处理其他事物,严格来说,我们仍然可以在activity里创建自己的worker thread或者async task之类做后台的事情,但这样做没有任何的保障,因为一旦我们所有的activity都被切换到了后台,系统随时可能kill掉我们的process,我们的后台任何随时可能悄无声息的死掉。

Activity为什么这样设计?因为这是移动设备,内存/电池都有限。

对我们的应用而言,通过manifest里声明Service,把需要后台相对长期运行的逻辑放在Service里,这样我们就获取了保障:只要系统内存不是极端不够用,我们的Service一定不会被kill掉。对系统而言,当看到一个进程里有Service在运行,这个进程就具有较高的优先级,会在内存不会被杀的行列里排得比较靠后。

我们可以把Service看成一坨代码,用来在后台做些事情,至于这坨代码再哪里运行,完全取决于自己。如果不新建立work thread,仍然是在UI线程中运行,如果不想阻塞UI线程,就可以建立一个work thread。这些细节,android framework并不怎么关心,它只知道我们声明了一个service,然后在mainfest里面找到这个service是声明在哪个process里的,那么这个process就不容易被kill。

什么时候选择local service(即不指定额外的进程),什么时候选择remote service(额外的进程)?通常我们会把真的需要长期运行的service(例如IM之类)放在单独的进程里,这样UI所在的进程在必要的时候仍然可 以被系统kill掉来腾出内存。而local service通常用来处理一些需要短期运行但仍然超出activity活动周期的任务,打个比方,发送短信或彩信。这样的任务执行完以 后,service就可以stop自己,仍然不妨碍整个UI进程被回收掉。

Service 生命周期:

在这里插入图片描述

左图显示了使用startService()所创建的服务的声明周期,右图显示了使用bindService()所创建服务的生命周期

Service的整个声明周期都是从调用onCreate()开始,到onDestroy()返回时结束。与Activity类似,服务也在onCreate()中完成初始化设置,并在onDestroy()中释放所有剩余资源。例如:音乐播放服务可以在 onCreate() 中创建用于播放音乐的线程,然后在 onDestroy() 中停止该线程。

服务的有效生命周期从调用 onStartCommand() 或 onBind() 方法开始。每种方法均有 Intent 对象,该对象分别传递到 startService() 或 bindService()。
对于启动服务,有效生命周期与整个生命周期同时结束(即便是在 onStartCommand() 返回之后,服务仍然处于活动状态)。对于绑定服务,有效生命周期在 onUnbind() 返回时结束。

可以调用stopSelf()或者stopService()来停止。

在使用Service的时候不要忘记在AndroidManifext.xml中注册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>

AndroidManifext里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

远程Service

远程 服务和本地服务最大的区别是:远程服务Service与调用者不在同一个进程里(即Service是运行在另外一个进程);而本地服务则是与调用者运行在同一个进程里。

远程服务的使用场景:

一般使用与为其他应用程序提供公共服务的Service,这种Service即为系统常驻的Service(如:天气服务等)。即多个应有程序共享同一个后台服务。也就是说一个远程Service与多个应用程序的组件进行跨进程通信。

说到跨进程通信(IPC),就需要使用AIDL了:

IPC:Inter-Process Communication,跨进程通信
AIDL:Android Interface Definition Language,即Android接口定义语言;用于让某个Service与多个应用程序组件之间进行跨进程通信,从而可以实现多个应用程序共享同一个Service的功能。

使用步骤:
Service:

  1. 新建定义AIDL文件,并声明该服务需要向客户端提供的接口
  2. 在Service子类中实现AIDL中定义的接口方法,并定义生命周期的方法(onCreate,onBind… …)
  3. 在AndroidManifest.xml中注册Service&声明为远程服务。

Client:

  1. 拷贝服务端的AIDL文件到目录下
  2. 使用 Stub.asInterface接口获取Service的BInder,根据需要调用Service提供的接口方法
  3. 通过Intent指定服务端的服务名和所在包,绑定远程Service。

使用:

首先创建两个AIDL文件
在这里插入图片描述

AIDL_Activity:用于Service向Activity通信的
AIDL_Service:用于Activity向Service通信的。

// AIDL_Activity.aidl
package com.example.asus1.remoteservice;

// Declare any non-default types here with import statements

interface AIDL_Activity {

    void onRespond(String s);
}

// AIDL_Service.aidl
package com.example.asus1.remoteservice;

// Declare any non-default types here with import statements
//一定要导包
import com.example.asus1.remoteservice.AIDL_Activity;

interface AIDL_Service {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */

    void sendMessage();

    void registerListener(AIDL_Activity lisntener);


}

然后写AIDL_Service的实现:

public class AidlBinder extends AIDL_Service.Stub {

    private RemoteService mService;
    private List<AIDL_Activity> mListeners = new ArrayList<>();

    public AidlBinder(RemoteService service){
        mService = service;
    }

    private static final String TAG = "RemoteService";

    @Override
    public void sendMessage()throws RemoteException {
        Log.d(TAG, "sendMessage: "+"通信了");
        for(int i = 0;i<mListeners.size();i++){
            mListeners.get(i).onRespond("message from service");
        }
    }

    @Override
    public void registerListener(AIDL_Activity lisntener) {
        mListeners.add(lisntener);
    }
}

创建Service:


public class RemoteService extends Service {

    private static final String TAG = "RemoteService";
    private AidlBinder mBinder = new AidlBinder(this);

    @Override
    public void onCreate() {
        Log.d(TAG, "onCreate: ");
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind: ");
        return mBinder;
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "onDestroy: ");
        super.onDestroy();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d(TAG, "onUnbind: ");
        return super.onUnbind(intent);
    }
    

注册Service:

 <service android:name=".RemoteService"
            android:process=":remote"
            android:exported="true"
            >
        </service>

在MAinActivity中绑定服务,发送消息:

public class MainActivity extends AppCompatActivity {


    private AIDL_Service mBinder;
    private static final String TAG = "MainActivity";

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mBinder = AIDL_Service.Stub.asInterface(service);
            try {
                mBinder.registerListener(new AIDL_Activity.Stub() {
                    private static final String TAG = "MainActivity";
                    @Override
                    public void onRespond(String s) throws RemoteException {
                        Log.d(TAG, "onRespond: "+s);
                    }
                });
            }catch (RemoteException ee){
                ee.printStackTrace();
            }
           
            try {
                mBinder.sendMessage();
            }catch (RemoteException e){
                e.printStackTrace();
            }

        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent(this,RemoteService.class);
        bindService(intent,mConnection, Context.BIND_AUTO_CREATE);

    }
    
}

看打印的消息:

 D/RemoteService: onCreate: 
    onBind: 
 D/RemoteService: sendMessage: 通信了

D/MainActivity: onRespond: message from service

这样就实现了跨进程通信!!!

进程的优先级:

Android系统将尽量长时间地保持应用进程,但为了新建进程或运行更重要的进程,最终需要移除旧进程来回收内存。为了确定保留或终止哪些进程,系统会根据进程中正在运行的组件以及这些组件的状态,将每个进程放入“重要性层次结构”中。必要时,系统会首先消除重要性最低的进程,依次类推,以回收系统资源。

  1. 前台进程(Foreground process):
    用户当前操作必须的进程;如果一个进程满足一下任一条件,即视为前台进程:

    1. 托管用户正在交互的Activity(以调用Activity的onResume方法)
    2. 托管某个Service,后者绑定到用户正在交互的Activity
    3. 托管正在“前台”运行的Service(Service已调用startForeground())
    4. 托管正在执行一个生命周期回调的Service(onCreate(),onStart()或onDestroy())
    5. 托管正执行其onReceive()方法的BroadcastReceiver
      通常,在任意给定事件 ,前台进程为数不多。只有在内存不足以支持它们同时继续运行这一万不得已的情况下,系统才会终止它们。 此时,设备往往已达到内存分页状态,因此需要终止一些前台进程来确保用户界面正常响应。
  2. 可见进程(Visible process)
    没有任何前台组件、但仍会影响用户在屏幕上所见内容的进程。 如果一个进程满足以下任一条件,即视为可见进程:
    1. 托管不在前台,但仍对用户可见的Activity(已调用其onPause()方法)。
    2. 托管绑定到可见(或前台)Activity的Service。
    可见进程被视为及其重要的进程,除非为了维持所有前台进程同时运行而必须终止,否则系统不会终止这些进程。

  3. 服务进程(Service process)
    正在运行已使用startService()方法启动的服务且不属于上述两个更高类别进程的进程。尽管服务进程与用户所见内容没有直接关联,但是它们通常在执行一些用户关心的操作(例如,在后台播放音乐或从网络下载数据)。因此,除非内存不足以维持所有前台进程和可见进程同时运行,否则系统会让服务进程保持运行状态。

  4. 后台进程(Background process)
    包含目前对用户不可见的Activity进程(以调用Activity的onStop()方法)。这些进程对用户体验没有直接影响,系统可能随时终止它们,以回收内存供前台进程,可见进程或服务进程使用。通常会有很多后台进程在运行,因此它们会保存在LRU列表中,以确保包含用户最近查看的Activity的进程最后一个被终止。如果某个Activity正确实现了生命周期方法并保存了当前状态,则终止其进程不会对用户体验产生明显影响,因为当用户回到该Activity时,Activity会恢复其所有可见状态。

  5. 空进程(Empty process)
    不含任何活动应用组件的进程。暴露这种进程的唯一目的是用作缓存,以缩短下次在其中运行组件所需的启动时间。 为使总体系统资源在进程缓存和底层内核缓存之间保持平衡,系统往往会终止这些进程。

上面我们有说到远程服务,它用到的就是Service中的bindService(),所以就来说说它:
绑定服务可让组件(例如Activity)绑定到Service,发送请求,接收响应,甚至执行进程间通信(IPC)。绑定服务通常只在为其他应用组件服务时处于活动状态,不会无限期在后台运行。

绑定服务是 Service 类的实现,可让其他应用与其绑定和交互。要提供服务绑定,您必须实现 onBind() 回调方法。该方法返回的 IBinder 对象定义了客户端用来与服务进行交互的编程接口。

我们可以通过三种方式定义接口:

扩展Binder类:

如果服务是共我们自己的应用专用的,并且在客户端相同的进程中运行,则用通过扩展Binder类并从onBind()返回它的一个实例来创建接口。
客户端收到 Binder 后,可利用它直接访问 Binder 实现中乃至 Service 中可用的公共方法。
如果服务只是您的自有应用的后台工作线程,则优先采用这种方法。 不以这种方式创建接口的唯一原因是,您的服务被其他应用或不同的进程占用。

public class FirstService extends Service {


    private CallBackInterface mCall;
    
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return new myBinder();
    }

    private class myBinder extends Binder{

        public FirstService getService(){

            return FirstService.this;
        }

    }
    
    public void response(){
        if(mCall!=null){
            mCall.response();
        }
    }
    
    public void registerInterface(CallBackInterface callBackInterface){
        mCall = callBackInterface;
    }

    public interface CallBackInterface{
        
        void response();
    }
}

可利用回调接口来实现Activity和Service的双向通信。

看一下Binder的介绍:

Base class for a remotable object, the core part of a lightweight
  remote procedure call mechanism defined by {@link IBinder}.
  This class is an implementation of IBinder that provides
  standard local implementation of such an object.

它是远程对象的基类,它是由IBinder定义的轻量级的远程调用机制。这个类实现了IBinder,IBinder提供此类的标准本地实现。

它里面有两个方法,我们看一下:

 public static final native int getCallingPid();
 public static final native int getCallingUid();

pid可与更高级别的系统服务一起使用,以确定其身份和检查权限。第一个方法是返回正在处理当前事务的进程ID,如果当前线程没有处理传进来的事务,就返回自己的pid。

uid可与更高级别的系统服务一起使用,以确定其身份和检查权限。它和pid的区别在于它返回的是linux的分配给进程的uid。

Messenger

如需让接口跨不同的进程工作,则可使用Messenger为服务创建接口。Service可以用这种方式定义不同类型Messager对象的Handler。此Handler是Message的基础,后者随后可与客户端分享一个IBinder,从而让客户端能利用Messenger对象想Service发送消息。此外,客户端还可以定义自用的Messenger,以便Service回传消息。
这是执行进程间通信的最简单的方法,因为Messager会在单一线程中创建包含所有请求的队列,这样就不必对服务进行线程安全设计。

以下是 Messenger 的使用方法:

  1. 服务实现一个 Handler,由其接收来自客户端的每个调用的回调
  2. Handler 用于创建 Messenger 对象(对 Handler 的引用)
  3. Messenger 创建一个 IBinder,服务通过 onBind() 使其返回客户端
  4. 客户端使用 IBinder 将 Messenger(引用服务的 Handler)实例化,然后使用后者将 Messenger 对象发送给服务
  5. 服务在其 Handler 中(具体地讲,是在 handleMessage() 方法中)接收每个 Message。
public class SecondService extends Service {

    private Messenger mServiceMess = new Messenger(new ServiceHandler());
    private Messenger mClientMess;
    public static final int REGISTER_CLIENT = 100;
    public static final int SAY_HELLO = 200;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mServiceMess.getBinder();
    }

    private class ServiceHandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case REGISTER_CLIENT:
                    mClientMess = (Messenger) msg.obj;
                    break;
                case SAY_HELLO:
                    System.out.println("from client");
                    try {
                        Message message = new Message();
                        message.what = SAY_HELLO;
                        mClientMess.send(message);
                    }catch (RemoteException e){
                        e.printStackTrace();
                    }

                    break;
            }
        }
    }
}

在Activity中:

 private class  ActivityHanlder extends Handler{

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case SecondService.SAY_HELLO:
                    System.out.println("from service");
                    break;
            }
        }
    }

    private Messenger mClient = new Messenger(new ActivityHanlder());
    private Messenger mService;

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            try {
                mService = new Messenger(service);
                Message message = new Message();
                message.what = SecondService.REGISTER_CLIENT;
                message.obj = mClient;
                mService.send(message);

                Message message1 = new Message();
                message1.what = SecondService.SAY_HELLO;
                mService.send(message1);
            }catch (RemoteException e){
                e.printStackTrace();
            }


        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

知道了它的用法后,我们先看看Messenger的介绍:

Reference to a Handler, which others can use to send messages to it.
  This allows for the implementation of message-based communication across
  processes, by creating a Messenger pointing to a Handler in one process,
  and handing that Messenger to another process.

大概是说,它关联到了一个Handler,可以用来发送消息。允许跨进程通信,通过在一个进程中创建一个指定Handler的Messenger,并将该Messenger交给另一个进程。

public final class Messenger implements Parcelable

它的构造方法:

private final IMessenger mTarget;

 public Messenger(Handler target) {
        mTarget = target.getIMessenger();
    }

public Messenger(IBinder target) {
        mTarget = IMessenger.Stub.asInterface(target);
    }

在Hanlder.java中

 final IMessenger getIMessenger() {
        synchronized (mQueue) {
            if (mMessenger != null) {
                return mMessenger;
            }
            mMessenger = new MessengerImpl();
            return mMessenger;
        }
    }


 private final class MessengerImpl extends IMessenger.Stub {
        public void send(Message msg) {
            msg.sendingUid = Binder.getCallingUid();
            Handler.this.sendMessage(msg);
        }
    }

在我们调用Messenger.send(Message )方法的时候:

 public void send(Message message) throws RemoteException {
        mTarget.send(message);
    }
    

我们可以看到,最终是调用IMessenger的send方法,而这个send方法,最终会调用MessengerImpl 的send方法。

与AIDL比较
当我们需要执行IPC时,为我们的接口使用Messenger要比使用AIDL实现它更加简单,因为Messenger会将所有服务调用排入队列,而纯粹的AIDL接口会同时向服务发送多个请求,服务随后必须对应多线程处理。
对于大多数应用,服务不需要执行多线程处理,因此使用Messenger可让服务一次处理一个调用。如果我们的服务必须执行多线程处理,则应使用AIDL来定义接口。

AIDL

AIDL(Android接口定义语言)执行所有将对象分解成原语的工作,操作系统可以识别这些原语并将它们编组到各进程中,以执行IPC。其实Messenger实际是以AIDL作为其底层结构。

注:只有允许不同应用的客户端用 IPC 方式访问服务,并且想要在服务中处理多线程时,才有必要使用 AIDL。 如果您不需要执行跨越不同应用的并发 IPC,就应该通过实现一个 Binder 创建接口;或者,如果您想执行 IPC,但根本不需要处理多线程,则使用 Messenger 类来实现接口。

调用情况:

  • 来自本地进程的调用,那么会在在发起调用的同一线程内执行。如果该线程是UI线程,那么该线程继续在AIDL接口中执行。如果该线程是其他线程,则便是Service中执行我们代码的线程。 因此,只有在本地线程访问服务时,我们才能完全控制哪些线程在服务中执行(但如果真是这种情况,我们根本不应该使用 AIDL,而是应该通过实现 Binder 类创建接口)。
  • 来自远程进程的调用,将分派给我们的自有进程内部维护的线程池。所以,我们必须为来自未知线程的多次并发传入调用做好准备。换言之,AIDL接口的实现必须是完成线程安全实现。
  • oneway 关键字用于修改远程调用的行为。使用该关键字时,远程调用不会阻塞;它只是发送事务数据并立即返回。接口的实现最终接收此调用时,是以正常远程调用形式将其作为来自 Binder 线程池的常规调用进行接收。 如果 oneway 用于本地调用,则不会有任何影响,调用仍是同步调用。

如需使用 AIDL 创建绑定服务,请执行以下步骤:

  1. 创建 .aidl 文件
    此文件定义带有方法签名的编程接口。

  2. 实现接口
    Android SDK 工具基于您的 .aidl 文件,使用 Java 编程语言生成一个接口。此接口具有一个名为 Stub 的内部抽象类,用于扩展 Binder 类并实现 AIDL 接口中的方法。您必须扩展 Stub 类并实现方法。

  3. 向客户端公开该接口
    实现 Service 并重写 onBind() 以返回 Stub 类的实现。

默认情况下,AIDL 支持下列数据类型:

  • Java 编程语言中的所有原语类型(如 int、long、char、boolean 等等)

  • String

  • CharSequence

  • List
    List 中的所有元素都必须是以上列表中支持的数据类型、其他 AIDL 生成的接口或您声明的可打包类型。 可选择将 List 用作“通用”类(例如,List)。另一端实际接收的具体类始终是 ArrayList,但生成的方法使用的是 List 接口。

  • Map
    Map 中的所有元素都必须是以上列表中支持的数据类型、其他 AIDL 生成的接口或您声明的可打包类型。 不支持通用 Map(如 Map<String,Integer> 形式的 Map)。 另一端实际接收的具体类始终是 HashMap,但生成的方法使用的是 Map 接口。

  • 您必须为以上未列出的每个附加类型加入一个 import 语句,即使这些类型是在与您的接口相同的软件包中定义。

定义服务接口时,请注意:

  • 方法可带零个或多个参数,返回值或空值。
  • 所有非原语参数都需要指示数据走向的方向标记。可以是 in、out 或 inout。
    原语默认为 in,不能是其他方向。

注意:您应该将方向限定为真正需要的方向,因为编组参数的开销极大。

  • .aidl 文件中包括的所有代码注释都包含在生成的 IBinder 接口中(import 和 package 语句之前的注释除外)
    只支持方法;您不能公开 AIDL 中的静态字段。

这个代码看过了,就不写…

通过IPC传递对象

通过 IPC 接口把某个类从一个进程发送到另一个进程是可以实现的。 不过,您必须确保该类的代码对 IPC 通道的另一端可用,并且该类必须支持 Parcelable 接口。支持 Parcelable 接口很重要,因为 Android 系统可通过它将对象分解成可编组到各进程的原语。

如需创建支持 Parcelable 协议的类,您必须执行以下操作:

  • 让您的类实现 Parcelable 接口。
  • 实现 writeToParcel,它会获取对象的当前状态并将其写入 Parcel。
  • 为您的类添加一个名为 CREATOR 的静态字段,这个字段是一个实现 Parcelable.Creator 接口的对象。
  • 最后,创建一个声明可打包类的 .aidl 文件。
    如果您使用的是自定义编译进程,切勿在您的编译中添加 .aidl 文件。 此 .aidl 文件与 C 语言中的头文件类似,并未编译。

AIDL 在它生成的代码中使用这些方法和字段将您的对象编组和取消编组。

package com.example.asus1.remoteservice;

import android.os.Parcel;
import android.os.Parcelable;

public class MSG implements Parcelable {

   public String msg;

    public  static final Parcelable.Creator<MSG> CREATOR = new Parcelable.Creator<MSG>(){

        @Override
        public MSG createFromParcel(Parcel source) {
            return new MSG(source);
        }

        @Override
        public MSG[] newArray(int size) {
            return new MSG[size];
        }
    };

    public MSG(String msg){
        this.msg = msg;
    }

    private MSG(Parcel parcel){
        readFromParcel(parcel);
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(msg);
    }

    public void readFromParcel(Parcel in){
         msg = in.readString();
    }
}

一定要创建MSG.aidl文件:


package com.example.asus1.remoteservice;
parcelable MSG;

在aidl接口中使用MSG的时候,一定要import和加上in/out/inout
in 表示客户端向服务端传递数据,当服务端的数据发生改变,不会影响到客户端
out表示服务端对数据修改,客户端会同步变动
inout表示客户端和服务端的数据总是同步的

发送:

  try {

                mBinder.sendMessage(new MSG("parcelable MSG"));
            }catch (Exception e){
                e.printStackTrace();
            }

Binder连接池

如果我们有很多业务模块需要使用AIDL来进行进程间通信,如果我们按照之前写的方式去创建多个Service,Service是四大组件之一,过多就会造成性能资源消耗,因此这个时候需要使用Binder连接池。

大致流程:
每个业务模块创建自己的AIDL接口并实现此接口,然后向服务端提供一个属于自己的key和其对应的对象,那么服务端只需要一个Service然后提供一个查询Binder的接口,然后根据业务模块来返回对应的BInder:

在这里插入图片描述

例子:
先写一个BinderPool.aidl:


interface IBinderPool {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    IBinder queryBinder(int binderCode);
}

分别写两个业务模块的aidl:

interface ICalculate {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
   int add(int first,int second);
   int sub(int first,int second);
}

interface IRect {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    int area(int length,int width);
    int perimeter(int length,int width);
}

然后分别实现这两个接口:

public class CalculateImpl extends ICalculate.Stub {

    @Override
    public int add(int first, int second) throws RemoteException {
        return first+second;
    }

    @Override
    public int sub(int first, int second) throws RemoteException {
        return first-second;
    }
}

public class RectImpl extends IRect.Stub {

    @Override
    public int area(int length, int width) throws RemoteException {
        return length*width;
    }

    @Override
    public int perimeter(int length, int width) throws RemoteException {
        return (length+width)*2;
    }
}

然后实现BinderPool,一定是单例!!!:


public class BinderPool {

    public static final int BINDER_NONE = -1;
    public static final int BINDER_CALCULATE = 0;
    public static final int BINDER_RECT = 1;

    private static final String TAG = "BinderPool";

    private Context mContext;
    private static IBinderPool mBinderPool;
    private static BinderPool mInstance;
    private CountDownLatch mCountDownLatch;

    private BinderPool(Context context){
        mContext = context;
        connectionService();//绑定Service
    }

    public static BinderPool getInstance(Context context){
        if(mInstance == null){
            synchronized (BinderPool.class){
                if(mInstance == null){
                    mInstance = new BinderPool(context);
                }
            }
        }

        return mInstance;
    }

    private ServiceConnection mBinderPoolConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mBinderPool = IBinderPool.Stub.asInterface(service);
            try {
                mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient,0);//防止BinderPool异常奔溃
            }catch (RemoteException e){

            }
            mCountDownLatch.countDown();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient,0);
            mBinderPool = null;
            if(mContext!=null){
                connectionService();
            }

        }
    };

    private  void connectionService(){
        mCountDownLatch = new CountDownLatch(1);
        mContext.bindService(new Intent(mContext,BinderPoolService.class)
                ,mBinderPoolConnection,Context.BIND_AUTO_CREATE);
        try {
            mCountDownLatch.await();//同步工具,让Service绑定成功后,再执行
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    public IBinder queryBidner(int binderCode){
        try {
            return mBinderPool.queryBinder(binderCode);
        }catch (RemoteException e){
            e.printStackTrace();
        }

        return null;
    }

    public static class BinderPoolIml extends IBinderPool.Stub{

        @Override
        public IBinder queryBinder(int binderCode) throws RemoteException {
            IBinder binder = null;
            switch (binderCode){
                case BINDER_CALCULATE:
                    binder = new CalculateImpl();
                    break;
                case BINDER_RECT:
                    binder = new RectImpl();
                    break;
            }
            return binder;
        }
    }

    public void unBinder(){
        mContext.unbindService(mBinderPoolConnection);
        mContext=null;
    }
}

Service就很简单了:

public class BinderPoolService extends Service {

    private Binder mBinderPool = new BinderPool.BinderPoolIml();

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mBinderPool;
    }
}

然后在Activity中:

   private BinderPool mBinderPool;
    private ICalculate mCalculate;
    private IRect mRect;
    private Handler mHander = new Handler(this);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        new Thread(new Runnable() {
            @Override
            public void run() {
                mBinderPool = BinderPool.getInstance(MainActivity.this);
                Log.d(TAG, "run: 11111111111");
                mHander.obtainMessage().sendToTarget();
                Log.d(TAG, "run: 22222222222222222");
            }
        }).start();




    }

    @Override
    public boolean handleMessage(Message msg) {

        mCalculate = ICalculate.Stub.asInterface(mBinderPool.queryBidner
                (BinderPool.BINDER_CALCULATE));
        mRect = IRect.Stub.asInterface(mBinderPool.queryBidner(BinderPool.BINDER_RECT));
      
        try {
            System.out.println(mCalculate.add(1,2));
            System.out.println(mRect.area(2,4));
        }catch (RemoteException e){
            e.printStackTrace();
        }
        
        return false;
    }

    @Override
    protected void onDestroy() {
     
        mBinderPool.unBinder();
        super.onDestroy();
    }

这样就实现了Binder连接池。

官方AIDL文档: https://developer.android.com/guide/components/aidl

猜你喜欢

转载自blog.csdn.net/qq_36391075/article/details/82955002