Aidl介绍 ----- 常见踩坑原因和解决方案

目录

0. 序言

1. 目录结构介绍

2. 界面及各按钮功能介绍

3. 各按钮代码执行逻辑介绍

4. 代码分析

5. 踩坑点和解决方案

6. 项目演示


0. 序言

最近开发中用到了AIDL,看了网上也有很多这方面的文章,写的都挺好,但是自己复现的时候会碰到各种问题,因此决定写一篇这方面的文章,提供一些容易踩坑的原因和解决方案,能力有限,如有分析错误,希望大家能积极的提出来。(注意:红色字体是比较重要的知识点)

1. 目录结构介绍

首先介绍一下本文的目录结构(具体想了解更多Android Studio中各个常见目录的作用,请看(占位符,预计2020.08完成)),该目录结构已经将本文所涉及到比较重要的各文件都罗列了出来,后面对这些文件在文章中的作用都会说明清楚。项目AidlDemo包含两个子模块:client和aidlservice,client主体部分是MainActivity和GeneralService。这个模块的作用是展示MainActivity是如何开启和结束GeneralService,如何绑定和解绑GeneralService。除了调用自己模块的服务,该MainAcivity还可以通过AIDL接口绑定和解绑aidlservice中的AidlService。需要注意的是,本文中aidlservice模块中MainActivity非核心,可以删除。

AidlDemo
   |--client
   |     |--build
   |     |     |--generated
   |     |     |      |--aidl_source_output_dir
   |     |     |                  |--debug
   |     |     |                       |--compileDebugAidl
   |     |     |                                  |--out
   |     |     |--outputs                             |--aidl
   |     |          |--apk                                 |--IAidlService.java-------(1)
   |     |              |--debug               
   |     |                   |--client-debug.apk--------------------------------------(2)                                      
   |     |--src
   |     |   |--main
   |     |        |--aidl
   |     |        |   |--IAidlService.aidl--------------------------------------------(3)
   |     |        |--java
   |     |        |    |--com.zhouxi.client
   |     |        |            |--GeneralService.java---------------------------------(4)
   |     |        |            |--MainActivity.java-----------------------------------(5)
   |     |        |--res
   |     |        |   |--layout
   |     |        |         |--activity_main.xml--------------------------------------(6)
   |     |        |--AndroidManifest.xml----------------------------------------------(7)
   |     |--build.gradle--------------------------------------------------------------(8)
   |     
   |--aidlservice
   |     |--build
   |     |     |--generated
   |     |     |     |--aidl_source_output_dir
   |     |     |                  |--debug
   |     |     |                       |--compileDebugAidl
   |     |     |                                |--out
   |     |     |--outputs                           |--aidl
   |     |           |--apk                              |--IAidlService.java---------(9)
   |     |               |--debug
   |     |                    |--aidlservice-debug.apk-------------------------------(10)
   |     |--src
   |     |   |--main
   |     |        |--aidl
   |     |        |   |--IAidlService.aidl-------------------------------------------(11)
   |     |        |--java
   |     |        |   |--com.zhouxi.service
   |     |        |             |--AidlService.java----------------------------------(12)
   |     |        |             |--MainActivity.java---------------------------------(13)
   |     |        |--res
   |     |        |   |--layout
   |     |        |         |--activity_main.xml-------------------------------------(14)
   |     |        |--AndroidManifest.xml---------------------------------------------(15)
   |     |--build.gradle-------------------------------------------------------------(16)
   |
   |--build.gradle-------------------------------------------------------------------(17)
   |--setting.gradle-----------------------------------------------------------------(18)
                                        
                                        AidlDemo目录结构

2. 界面及各按钮功能介绍

第一张图模拟客户端client,包含了START SERVICE、STOP SERVICE、BIND SERVICE、UNBIND SERVICE、BIND AIDL SERVICE和UNBIND AIDL SERVICE六个按钮。

  • 前两个按钮提供同一个模块中的GeneralService的启动和关闭,两者不存在绑定关系。
  • 中间两个按钮提供了绑定和解绑同一个模块中GeneralService的功能。
  • 后面两个按钮提供了client中的MainActivity使用AIDL接口绑定和解绑aidlservice中AidlService的功能。

(注意:aidlservice的MainActivity非必须,AidlService可以单独作为一个后台服务,因此右图的aidlservice可以不需要界面,特意设计两个按钮主要是为了调试)

serviceclient

3. 各按钮代码执行逻辑介绍

3.1 START SERVICE和STOP SERVICE 

这种服务启动方式仅仅是把GeneralService启动了,但是两者没有绑定关系,也就是说当MainActivity不再运行了,GeneralService不会随之关闭,当然MainActivity可以提供手动关闭GeneralService的功能。

  • START SERVICE 只需要将当前的类名和需要跳转的类名放入到intent中,直接执行startService(intent)就可以启动GeneralService。
Intent intent = new Intent(this, GeneralService.class);
startService(intent);
  • STOP SERVICE 和开启服务方式类似,只需将startService改成stopService即可。
Intent intent = new Intent(this, GeneralService.class);
stopService(intent);

3.2 BIND SERVICE和UNBIND SERVICE

和上面单纯的开启和关闭服务不同的是,这种启动服务的方式使得GeneralService的服务周期和MainActivity绑定,一旦MainActivity关闭,GeneralService也会随之关闭(注意:反之,当GeneralService关闭,MainAcitivy并不会随之关闭)。具体来说:

  • BIND SERVICE 绑定服务需要用到bindService,需要传入Intent、ServiceConnection、flag三个参数。其中Intent主要是记录了MainActivity和GeneralService之间传递的信息,由于两者属于同一个模块,也就是同一个apk中,因此只需要传入两者的类名就行(注意这点和使用AIDL接口跨apk之间调用的区别)。
Intent intent = new Intent(this, GeneralService.class);
bindService(intent, serviceConnection, BIND_AUTO_CREATE);
  • ServiceConnection的作用是用来监督两者绑定的状态,同时接收从GeneralService传递过来的IBinder对象,ServiceConnection实现了onServiceConnected和onServiceDisconnected,其中onServiceConnected绑定成功后会回传回一个IBinder对象.
public ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e(TAG, "onServiceConnected: bind GeneralService success.");
            GeneralService.GeneralBinder generalBind = (GeneralService.GeneralBinder) service;
            generalBind.readWriteInfo();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(TAG, "onServiceDisconnected: bind GeneralService fail.");
        }
    };
  • 而这个对象是GeneralService一个内部类。
class GeneralBinder extends Binder {
    public void readWriteInfo() {
        String info = readServiceInfo();
        Log.e(TAG, "getInfo: readServiceInfo success, the information: " + info);
        writeServiceInfo("This is writeServiceInfo in GeneralBinder.");
        Log.e(TAG, "getInfo: writeServiceInfo success.");
    }
}
  • 为什么还需要定义一个内部类?因为一般来说MainActivity不能直接访问GeneralService中的方法,因此通过GeneralService定义一个内部类,该内部类可以定义一些方法,这些方法调用GeneralService访问的方法,MainActivity也就间接的实现了访问GeneralService中的方法。
  • UNBIND SERVICE 解绑需要用到unbindService,输入的参数只有ServiceConnection,需要注意的是,解绑的时候只会执行GeneralService中onUnbind和onDestroy方法,而ServiceConnection中的onServiceDisconnected只针对绑定时出错的时候返回,解绑时并不会执行该方法
unbindService(aidlServiceConnection);

3.3 BIND AIDL SERVICE和UNBIND AIDL SERVICE 

这种绑定方式和上述的绑定方式类似,区别在于上述的MainActivity和GeneralService在同一个模块下,也就是同一个apk,MainActivity在启动GeneralService的时候直接输入类名就可以很方便的找到GeneralService的位置。而当MainActivity和AidlService在不同的apk时,也就是说一个apk想要访问另一个apk中的服务功能,就需要使用AIDL接口来提供一个中间桥梁,实现跨apk之间的功能调用。(注意:apk不一定有界面哦,单独的一个AidlService也可以打包成apk作为后台服务,这个和apk安装的目录有关,比如系统目录,该目录下的apk无法在手机桌面上看到,属于不可见的系统服务,但是安装过程中需要root权限,普通的目录一般都会有个界面,同时手机上能看到对应的软件)

  • BIND AIDL SERVICE 与BIND SERVICE类似,两者都调用了bindService(Intent, ServiceConnection, flag),区别在于Intent和ServiceConnection。对于Intent,由于BIND SERVICE绑定的服务和自身属于同一个APK,自身可以很容易的通过类名找到对应的服务。而BIND AIDL SERVICE绑定的服务与自身属于不同的APK,在绑定过程中就需要通过包名和对应的ACTION来寻找绑定的服务。
Intent intent = new Intent();
intent.setAction("com.zhouxi.service.AidlService");
intent.setPackage("com.zhouxi.service");
bindService(intent, aidlServiceConnection, Context.BIND_AUTO_CREATE);
  • 对于ServiceConnection,两者使用的是同一个类,只是在传回的IBinder对象不同(注意:需要用不同类型的变量来接收)
public ServiceConnection aidlServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        Log.e(TAG, "onServiceConnected: bind AidlService success.");
        IAidlService aidlService = IAidlService.Stub.asInterface(service);
        try {
            Log.e(TAG, "onServiceConnected: the info of AidlService: " + aidlService.getServiceInfo());
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        Log.e(TAG, "onServiceConnected: bind AidlService fail.");
    }
};
  • GeneralService自己在内部定义继承自IBinder的内部类,通过在onBinder将该类型的对象返回给onServiceConnected。而AidlService也是通过自定义内部类来提供调用者服务的功能,但是该内部类继承自IAidlService.Stub,仅此而已,他们本质上都是通过定义内部类,并把内部类的对象传给客户端,从而实现客户端调用服务的目的。
//两个内部类对比
class GeneralBinder extends Binder {
    public void readWriteInfo() {
        String info = readServiceInfo();
        Log.e(TAG, "getInfo: readServiceInfo success, the information: " + info);
        writeServiceInfo("This is writeServiceInfo in GeneralBinder.");
        Log.e(TAG, "getInfo: writeServiceInfo success.");
    }
}
================================================================================
class AidlBinder extends IAidlService.Stub {
    @Override
    public String getServiceInfo() {
        Log.e(TAG, "getServiceInfo: This is getServiceInfo in AidlBinder.");
        return info;
    }
}
  • 查看onServiceConnected的入参,可以发现无论是否采用AIDL的方法,第二个参数都是IBinder类型。虽然现在我们不知道两个内部类继承的父类Binder和IAidlService.Stub的关系,但是有一点可以确定的是,两个都是IBinder类型。通过这么对比,两者的区别已经很明朗了。那么IAdlService是什么?IAidlService.Stub又是什么,两者又有什么区别,具体的分析请参考这篇文章(占位:预计2020.7.21号完成)回到两个内部类的对比,GeneralService的内部类直接定义了一个方法,通过这个方法来获取GeneralService提供的功能,AidlService的内部类通过实现IAidlService接口的方法来获取服务提供的功能。
  • UNBIND AIDL SERVICE 解绑和GeneralService的解绑方式一样,就不再介绍了。
unbindService(aidlServiceConnection);

4. 代码分析

这是client模块的MainActivity,也就是上图中六个按钮的界面,该类定义了六个按钮,用来实现开启关闭GeneralService,绑定解绑GeneralService,绑定解绑另一个apk中的AidlService。

定义了两个ServiceConnected:serviceConnected和aidlServiceConnected分别用来检测是否绑定成功,如果绑定成功的话,分别接收服务所传回来的IBinder对象。

package com.zhouxi.client;

import aidl.IAidlService;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    public static final String TAG = MainActivity.class.getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.startGeneralService).setOnClickListener(this);
        findViewById(R.id.stopGeneralService).setOnClickListener(this);
        findViewById(R.id.bindGeneralService).setOnClickListener(this);
        findViewById(R.id.unbindGeneralService).setOnClickListener(this);
        findViewById(R.id.bindAidlService).setOnClickListener(this);
        findViewById(R.id.unbindAidlService).setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.startGeneralService) {
            Intent intent = new Intent(this, GeneralService.class);
            startService(intent);
        } else if (v.getId() == R.id.stopGeneralService) {
            Intent intent = new Intent(this, GeneralService.class);
            stopService(intent);
        } else if (v.getId() == R.id.bindGeneralService) {
            Intent intent = new Intent(this, GeneralService.class);
            bindService(intent, serviceConnection, BIND_AUTO_CREATE);
        } else if (v.getId() == R.id.unbindGeneralService) {
            unbindService(serviceConnection);
        } else if (v.getId() == R.id.bindAidlService) {
            Intent intent = new Intent();
            intent.setAction("com.zhouxi.service.AidlService");
            intent.setPackage("com.zhouxi.service");
            bindService(intent, aidlServiceConnection, Context.BIND_AUTO_CREATE);
        } else if (v.getId() == R.id.unbindAidlService) {
            Log.e(TAG, "onClick: unbindAidlService");
            unbindService(aidlServiceConnection);
        }
    }

    public ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e(TAG, "onServiceConnected: bind GeneralService success.");
            GeneralService.GeneralBinder generalBind = (GeneralService.GeneralBinder) service;
            generalBind.readWriteInfo();
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(TAG, "onServiceDisconnected: bind GeneralService fail.");
        }
    };

    public ServiceConnection aidlServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e(TAG, "onServiceConnected: bind AidlService success.");
            IAidlService aidlService = IAidlService.Stub.asInterface(service);
            try {
                Log.e(TAG, "onServiceConnected: the info of AidlService: " + aidlService.getServiceInfo());
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(TAG, "onServiceConnected: bind AidlService fail.");
        }
    };
}

 GeneralService继承自Service,实现了Service的onBind和onUnbind方法,当有MainActivity调用开启服务后,执行onBind方法,返回内部类的实例,该内部类定义了一些方法用来调用GeneralService内部的方法,间接的让MainActivity调用了GeneralService的方法。当MainActivity解绑后,执行onUnbind方法。

package com.zhouxi.client;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;

public class GeneralService extends Service {
    private static final String TAG = GeneralService.class.getSimpleName();

    private String info = "This is GeneralService info.";

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

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

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

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onBind: GeneralService is onBind.");
        return new GeneralBinder();
    }

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

    class GeneralBinder extends Binder {
        public void readWriteInfo() {
            String info = readServiceInfo();
            Log.e(TAG, "getInfo: readServiceInfo success, the information: " + info);
            writeServiceInfo("This is writeServiceInfo in GeneralBinder.");
            Log.e(TAG, "getInfo: writeServiceInfo success.");
        }
    }

    public String readServiceInfo() {
        Log.e(TAG, "readServiceInfo: this is readServiceInfo in GeneralService.");
        return info;
    }

    public void writeServiceInfo(String info) {
        Log.e(TAG, "writeServiceInfo: this is writeServiceInfo in GeneralService.");
        this.info = info;
    }
}

这是client模块的AndroidManifest文件,主要关注一下包名 package="com.zhouxi.client"和两个组件(Android中的四大组件不知道的可以复习一下)的注册信息。这个注册信息有啥用:一般来说,四大组件需要使用的话必须要在AndroidManifest中注册(声明),不然当apk执行过程中需要调用组件,系统会去这个xml文件中找一下这个apk中是不是有这个组件名,没有的话会直接闪退,这也是安卓apk调试中常见的闪退原因。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.zhouxi.client">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        //MainActivity注册信息
        <activity android:name="com.zhouxi.client.MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        //GeneralService注册信息
        <service android:name="com.zhouxi.client.GeneralService"/>
    </application>

</manifest>

IAidlService接口是MainActivity和AidlService沟通的桥梁, 接口中定义了getServiceInfo方法,AidlService定义了一个继承自IAidlService.Stub的内部类AidlBinder,上面已经分析过了,通过查看aidlServiceConnected的onServiceConnected的入参,可以判断IAidlService.Stub是IBinder类型的对象,具体是什么,请继续学习下一节(占位:预计2020.7.20完成),在这里我们可以把这个AidlBinder内部类想象成另一个服务中的GeneralBinder,他们整体的步骤其实是差不多的,只是AidlBinder内部类由于继承了IAidlService接口,所以内部需要实现该接口定义的方法。然后MainActivity通过这个内部类定义的方法间接的访问AidlService的功能。

// IAidlService.aidl
package aidl;

interface IAidlService {
    String getServiceInfo();
}
package com.zhouxi.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

import aidl.IAidlService;
import androidx.annotation.Nullable;

public class AidlService extends Service {
    private static final String TAG = AidlService.class.getSimpleName();

    private String info = "This is AidlService info.";

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

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

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

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.e(TAG, "onBind: AidlService is onBind.");
        return new AidlBinder();
    }

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

    class AidlBinder extends IAidlService.Stub {
        @Override
        public String getServiceInfo() {
            Log.e(TAG, "getServiceInfo: This is getServiceInfo in AidlBinder.");
            return info;
        }
    }
}

这是aidlservice模块的AndroidManifest文件, 上面已经介绍过了,这里就只介绍intent-filter这个特性,查看MainActivity启动AidlService的过程:Intent中传入了Action和Package,Intent的作用主要是为了传递信息的,在这里就是要在bindService的时候告诉系统我现在要去绑定的服务的包名是什么,为什么不能像前面的一样直接写类名,因为这是两个apk啊,肯定需要通过中间人也就是操作系统来查找,同时定义的Action的作用可以理解为两个apk之间调用的“暗号”,你在AndroidManifest中定义了这个特性,我在寻找服务的时候也注入这个“暗号”,那我不就可以找到你了么。

Intent intent = new Intent();
intent.setAction("com.zhouxi.service.AidlService");
intent.setPackage("com.zhouxi.service");
bindService(intent, aidlServiceConnection, Context.BIND_AUTO_CREATE);
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.zhouxi.service">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        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
            android:name=".AidlService">
            <intent-filter>
                <action android:name="com.zhouxi.service.AidlService"/>
            </intent-filter>
        </service>
    </application>

</manifest>

 main_activity文件就不说了,定义了六个按钮用来展示在首页并提供单击响应功能。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.zhouxi.client.MainActivity">

    <Button
        android:id="@+id/startGeneralService"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Start service"/>

    <Button
        android:id="@+id/stopGeneralService"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Stop service"/>

    <Button
        android:id="@+id/bindGeneralService"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Bind service"/>

    <Button
        android:id="@+id/unbindGeneralService"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="unbind service"/>

    <Button
        android:id="@+id/bindAidlService"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Bind aidl service"/>

    <Button
        android:id="@+id/unbindAidlService"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Unbind aidl service"/>

</LinearLayout>

5. 踩坑点和解决方案

在测试之前,先来整理一下本文的Demo一些容易踩坑的地方,这也是本文最需要关注的地方,可能可以解决你碰到的很多坑。

1. 为什么我的apk在运行过程中出现闪退现象?

解决方案一:着重关注一下AndroidManifest文件,看看该文件中是否已经注册了相应的组件,如果没有注册相应的组件,而恰好该组件被调用了,那么就会出现闪退。

解决方案二:代码中如果有Exception也会出现闪退,因此在平常编码中就要养成良好的日志打印习惯,尝试着使用日志来定位问题,如何使用日志高效的定位问题,请参照这篇文章(占位:预计2020.08完成)

2. 为什么服务中的内部类在实现接口的时候显示找不到该接口?

要想客户端和服务器两边的AIDL接口能提供给自身的类调用,同时两个apk之间实现通信,需要满足以下几个条件:

  1. 参照最上面的AidlDemo目录结构的(3),必须存在aidl包,同时aidl包必须与java同一级,IAidlService.aidl文件必须保存在aidl下面,可以直接保存在aidl下面,也可以在aidl下面新建包保存。
  2. 包名必须要和IAidlService.aidl类中最上面的包名对应。
  3. 需要提前编译,编译后的结果会保存在(1)中,没有这个文件无法引入IAidlService,会编译报错。
  4. 客户端和服务器端的IAidlService所在的包名必须要相同。需要注意的是,前三条不满足条件会编译不通过。如果前三条都满足第四条不满足,程序能正常运行,但是当跨apk调用的时候会闪退。

具体想了解更多关于AIDL接口的存放位置,请看这篇(占位,预计2020.07.20完成)

6. 项目演示

接下来就来验证以下效果,依次点击六个按钮,打印的日志如下,通过日志我们可以发现各函数的调用关系:

START SERVICE: 开启服务后直接调用GeneralService服务的onCreate->onStartCommand

STOP SERVICE: 关闭服务直接调用GeneralService服务的onDestroy

BIND SERVICE: 绑定服务后首先服务开启AidlService服务的onCreate->调用服务的onBind方法并返回IBinder对象->onServiceConnected方法接收到服务返回的对象->主函数调用该对象的方法来访问GeneralService的内部方法。

UNBIND SERVICE:解绑服务后GeneralService调用onBind->onDestroy。

BIND AIDL SERVICE和UNBIND AIDL SERVICE和上述的绑定过程类似,就不详细介绍。

下面是六个按钮依次点击的日志,通过日志并结合上面代码更容易理解函数的调用过程。

//START SERVICE
2020-07-15 00:34:47.208 13981-13981/com.zhouxi.client E/GeneralService: onCreate: GeneralService is onCreate.
2020-07-15 00:34:47.209 13981-13981/com.zhouxi.client E/GeneralService: onStartCommand: GeneralService is onStartCommand.

//STOP SERVICE
2020-07-15 00:34:50.445 13981-13981/com.zhouxi.client E/GeneralService: onDestroy: GeneralService is onDestroy.

//BIND SERVICE
2020-07-15 00:34:51.578 13981-13981/com.zhouxi.client E/GeneralService: onCreate: GeneralService is onCreate.
2020-07-15 00:34:51.578 13981-13981/com.zhouxi.client E/GeneralService: onBind: GeneralService is onBind.
2020-07-15 00:34:51.580 13981-13981/com.zhouxi.client E/MainActivity: onServiceConnected: bind GeneralService success.
2020-07-15 00:34:51.580 13981-13981/com.zhouxi.client E/GeneralService: readServiceInfo: this is readServiceInfo in GeneralService.
2020-07-15 00:34:51.580 13981-13981/com.zhouxi.client E/GeneralService: getInfo: readServiceInfo success, the information: This is GeneralService info.
2020-07-15 00:34:51.580 13981-13981/com.zhouxi.client E/GeneralService: writeServiceInfo: this is writeServiceInfo in GeneralService.
2020-07-15 00:34:51.580 13981-13981/com.zhouxi.client E/GeneralService: getInfo: writeServiceInfo success.

//UNBIND SERVICE
2020-07-15 00:34:52.321 13981-13981/com.zhouxi.client E/GeneralService: onUnbind: GeneralService is onUnbind.
2020-07-15 00:34:52.321 13981-13981/com.zhouxi.client E/GeneralService: onDestroy: 
GeneralService is onDestroy.

//BIIND AIDL SERVICE
2020-07-15 00:34:53.044 13981-13981/com.zhouxi.client E/MainActivity: onServiceConnected: bind AidlService success.
2020-07-15 00:34:53.046 13981-13981/com.zhouxi.client E/MainActivity: onServiceConnected: the info of AidlService: This is AidlService info.

//UNBIND AIDL SERVICE
2020-07-15 00:34:53.683 13981-13981/com.zhouxi.client E/MainActivity: onClick: unbindAidlService

 

猜你喜欢

转载自blog.csdn.net/weixin_48968045/article/details/107216295
今日推荐