android AIDL

本文详细介绍了Android中的AIDL(Android Interface Definition Language)如何用于跨进程通信。通过AIDL,服务端可以定义接口,客户端通过Binder调用服务端的方法。文中展示了服务端创建AIDL文件、实现接口、注册服务,以及客户端复制AIDL文件、绑定服务并调用接口的完整步骤。最终,通过示例验证了服务端与客户端之间的通信成功。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考博客:https://blog.youkuaiyun.com/carson_ho/article/details/53160279?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160397019719215646526443%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=160397019719215646526443&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v1~rank_blog_v1-1-53160279.pc_v1_rank_blog_v1&utm_term=AIDL&spm=1018.2118.3001.4450

AIDL是什么:

  • Android 接口定义语言(Android interface define language)。用于生成可以在Android设备上两个进程通讯(IPC interprocess communication)的代码。其方法不能重载,因为相同的方法底层映射都是相同的ID;
  • 支持的类型:
  1. Java中的八种基本数据类型。
  2. CharSequence / String类型
  3. Parcelable类型
  4. List /Map 类型

AIDL的优点:

  • 跨进程,多并发。

具体使用

  • 在多进程通信中,存在两个进程角色(以最简单的为例):服务器端和客户端

  • 以下是两个进程角色的具体使用步骤:
    服务器端(Service)
    步骤1:新建定义AIDL文件,并声明该服务需要向客户端提供的接口
    步骤2:在Service子类中实现AIDL中定义的接口方法,并定义生命周期的方法(onCreat、onBind()等)
    步骤3:在AndroidMainfest.xml中注册服务 & 声明为远程服务

    客户端(Client)
    步骤1:拷贝服务端的AIDL文件到目录下
    步骤2:使用Stub.asInterface接口获取服务器的Binder,根据需要调用服务提供的接口方法
    步骤3:通过Intent指定服务端的服务名称和所在包,绑定远程Service

一:服务端

步骤1. 新建一个AIDL文件

步骤2. 在新建AIDL文件里定义Service需要与Activity进行通信的内容(方法),并进行编译(Make Project)

// IMyAidlInterface.aidl
package com.example.androidpratic;

// 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 startApp();
}

步骤3:在Service子类中实现AIDL中定义的接口方法,并定义生命周期的方法(onCreat、onBind()等)

package service;

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

import com.example.androidpratic.IMyAidlInterface;

public class AidlService extends Service {
    private static final String TAG = "AidlService";

    public AidlService() {
    }

    IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() {
        @Override
        public void startApp() throws RemoteException {
            Log.d(TAG, "startApp.......");
        }
    };

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

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

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

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

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

步骤4:在AndroidMainfest.xml中注册服务 & 声明为远程服务

 <service
   android:name="service.AidlService"
   android:process=":remote"
   android:enabled="true"
   android:exported="true">

   <!-- 此处Intent的action必须写成“服务器端包名.aidl文件名” -->
   <intent-filter>
       <action android:name="com.example.androidpratic.IMyAidlInterface"/>
   </intent-filter>
 </service>

二:客户端

步骤1:将服务端的AIDL文件所在的包复制到客户端目录下(Project/app/src/main),并进行编译

// IMyAidlInterface.aidl
package com.example.androidpratic;

// 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 startApp();
}

步骤2:在主布局文件定义“启动APP”的按钮

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/start_app"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

步骤3:在MainActivity.java里

  • 使用Stub.asInterface接口获取服务器的Binder;
  • 通过Intent指定服务端的服务名称和所在包,进行Service绑定;
  • 根据需要调用服务提供的接口方法。
package com.example.aidlclient;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ComponentName;
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;
import android.widget.Button;

import com.example.androidpratic.IMyAidlInterface;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private IMyAidlInterface mMyAidlInterface;

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            Log.d(TAG, "onServiceConnected: " + (iBinder == null));
            if (iBinder != null) {
                mMyAidlInterface = IMyAidlInterface.Stub.asInterface(iBinder);
                try {
                    mMyAidlInterface.startApp();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mMyAidlInterface = null;
        }
    };

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

        Button startBtn = findViewById(R.id.start);
        startBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //通过Intent指定服务端的服务名称和所在包,与远程Service进行绑定
                //参数与服务器端的action要一致,即"服务器包名.aidl接口文件名"
                Intent intent = new Intent("com.example.androidpratic.IMyAidlInterface");
                intent.setPackage("com.example.androidpratic");
                bindService(intent, mConnection, BIND_AUTO_CREATE);
            }
        });
    }
}

三:运行结果

如下图所示,在client端点击了三次,server端都打印了对应log,说明通信成功。

四:补充

今天重新打开代码,运行了一下发现as里面打不出log,郁闷了一会(之前怎么有),后来发现之前都是在cygwin里面看的,所以又去试了一下,果然行。

这次准备再服务端的startApp中添加一个操作,当客户端点击按钮时,可以直接启动服务端activity。修改代码如下:

 IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() {
        @Override
        public void startApp() throws RemoteException {
            Log.d(TAG, "startApp.......");
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    Intent intent = new Intent(getApplicationContext(), MainActivity.class);
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(intent);
                }
            });
        }
    };

得要加一个flag,另开一个栈来存放新app的activity。不然会报错:

android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

后记:IMyAidlInterface.Stub()只是获取binder对象,进程通信本质就是通过传输binder对象,服务端或者客户端只要获取到了对方的binder对象就可以调用对方的方法,不是只有服务端才实现.Stub()方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值