Android AIDL 学习使用

来源:https://developer.android.com/guide/components/aidl

        最近没事看了下Google对于AIDL的说明,自己理解了一下,做一下笔记,笔记中的代码都是自己敲出来的,之前自己看别人的文章服务端和客户端都在一个应用里,虽然指定了UID但是总感觉差了点,于是就自己试了一下服务端和客户端在不同的应用中的写法

一   google官方说明

The Android Interface Definition Language (AIDL) is similar to other IDLs you might have worked with. It allows you to define the programming interface that both the client and service agree upon in order to communicate with each other using interprocess communication (IPC). On Android, one process cannot normally access the memory of another process. So to talk, they need to decompose their objects into primitives that the operating system can understand, and marshall the objects across that boundary for you. The code to do that marshalling is tedious to write, so Android handles it for you with AIDL.

Note: Using AIDL is necessary only if you allow clients from different applications to access your service for IPC and want to handle multithreading in your service. If you do not need to perform concurrent IPC across different applications, you should create your interface by implementing a Binder or, if you want to perform IPC, but do not need to handle multithreading, implement your interface using a Messenger. Regardless, be sure that you understand Bound Services before implementing an AIDL.

Before you begin designing your AIDL interface, be aware that calls to an AIDL interface are direct function calls. You should not make assumptions about the thread in which the call occurs. What happens is different depending on whether the call is from a thread in the local process or a remote process. Specifically:

  • Calls made from the local process are executed in the same thread that is making the call. If this is your main UI thread, that thread continues to execute in the AIDL interface. If it is another thread, that is the one that executes your code in the service. Thus, if only local threads are accessing the service, you can completely control which threads are executing in it (but if that is the case, then you shouldn't be using AIDL at all, but should instead create the interface by implementing a Binder).
  • Calls from a remote process are dispatched from a thread pool the platform maintains inside of your own process. You must be prepared for incoming calls from unknown threads, with multiple calls happening at the same time. In other words, an implementation of an AIDL interface must be completely thread-safe.
  • The oneway keyword modifies the behavior of remote calls. When used, a remote call does not block; it simply sends the transaction data and immediately returns. The implementation of the interface eventually receives this as a regular call from the Binder thread pool as a normal remote call. If oneway is used with a local call, there is no impact and the call is still synchronous.

看了google对aidl的定义,因为是英文的,看的有点懵懵懂懂的,如果有英文比较好的大佬能帮忙翻译理解一下,然后用通俗易懂的方式留下言就万分感谢了

我自己理解了一下,大概就是有多个应用访问同一个服务而且想要在服务端做多线程处理的时候google才建议使用aidl

二  使用aidl

     1 创建aidl文件IMyAidlInterface.aidl

// IMyAidlInterface.aidl
package com.example.cslrcj.myaidltest1;
import com.example.cslrcj.myaidltest1.Persion;
// Declare any non-default types here with import statements

interface IMyAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void add(in Persion persion);
    List<Persion> getPersion();
    int getPid();
}

      由于aidl本身支持数据类型如下:

  • Java 编程语言中的所有原语类型(如 intlongcharboolean 等等)
  • String
  • CharSequence
  • List

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

  • Map

    Map 中的所有元素都必须是以上列表中支持的数据类型、其他 AIDL 生成的接口或您声明的可打包类型。 不支持通用 Map(如 Map<String,Integer> 形式的 Map)。 另一端实际接收的具体类始终是 HashMap,但生成的方法使用的是 Map 接口。
    但是在实际工作中我们可能需要传一些自己定义的类,如果这样的话我们必须将我们自己定义的类序列化,不然是不能传的,我这里面也是加了一个自己定义的类Persion,贴下一我的代码:
    在IMyAidlInterface.aidl文件的同级目录下创建Persion.aidl

// IPersion.aidl
package com.example.cslrcj.myaidltest1;

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

parcelable Persion;

aidl文件是有些编写规则的:

1 除了aidl本身支持的那些数据类型,其他我们自己定义的如果有用到必须用import导入才可以

2  方法可带零个或多个参数,返回值或空值
3  所有非原语参数都需要指示数据走向的方向标记。可以是 in、out 或 inout(见以下示例)。 ----默认是in 这个最好标记正确,比较对内存开销比较大

2  服务端编写

创建一个service,实现onbind方法返回自己的aidl,代码如下:

public class MyIntentService extends IntentService {
    @Override
    public IBinder onBind(Intent intent) {
        return myBinder;
        //return super.onBind(intent);
    }

    public IBinder myBinder = new IMyAidlInterface.Stub() {
        @Override
        public void add(Persion persion) throws RemoteException {

        }

        @Override
        public List<Persion> getPersion() throws RemoteException {
            return null;
        }

        @Override
        public int getPid() throws RemoteException {
            return Process.myUid();
        }
    };

当客户端(如 Activity)调用 bindService() 以连接此服务时,客户端的 onServiceConnected() 回调会接收服务的 onBind() 方法返回的 mBinder 实例。

3 客户端使用

由于是在不同的应用中,所以我们需要将aidl相关的配置都复制到客户端,并且包名都应该一样才可以使用,客户端代码:

public class MainActivity extends AppCompatActivity {
    IMyAidlInterface myAidlInterface;
    List<Persion> mPersionList = new ArrayList<>();
    private TextView tv_show_persion;
    int serviceUid;
    ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myAidlInterface = IMyAidlInterface.Stub.asInterface(service);
            try {

                myAidlInterface.add(new Persion(12, "lisi"));
                mPersionList = myAidlInterface.getPersion();
                serviceUid = myAidlInterface.getPid();

            } 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);
        tv_show_persion = findViewById(R.id.tv_show_persion);
        Intent mIntent = new Intent("com.example.cslrcj.myaidltest1.MyIntentService");
        mIntent.setPackage("com.example.cslrcj.myaidltest1");
        bindService(mIntent, serviceConnection, Service.BIND_AUTO_CREATE);
    }

这样差不多就行了,附带一下项目的结构图

猜你喜欢

转载自blog.csdn.net/yangfan1571397878/article/details/82900301