IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> AIDL使用 -> 正文阅读

[移动开发]AIDL使用

作者:token keyword

概述

  • Android开发过程中AIDL使用
  • Android Studio版本:Android Studio Arctic Fox
  • targetSdk 31

AIDL开发步骤

1、创建.aidl文件件

创建.aidl文件
aidl文件内容示例(定义业务接口)

// BookController.aidl
package com.example.binderdemo;

import com.example.binderdemo.Book;

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

interface BookController {

   List<Book> getBookList();

   //注意当tag定义为out时,服务端会新创建一个Book实例,所以Book类必须得有无参构造函数
   void addBook(in Book book);

   Book getBook(in int pos);
}

AIDL支持的数据类型

  • Java 编程语言中的所有原始类型(如 int、long、char、boolean 等)
  • String和CharSequence;
  • List:只支持ArrayList,里面每个元素都必须能够被AIDL支持;
  • Map:只支持HashMap,里面的每个元素都必须被AIDL支持,包括key和value;
  • Parcelable:所有实现了Parcelable接口的对象;
  • AIDL:所有的AIDL接口本身也可以在AIDL文件中使用.

in、out、inout简单总结

  • in:服务端修改不同步到客户端对象,可以看作不是同一个对象,
  • out 客户端传递对象无效,实际传值为新创建对象到服务端,可以看作返回一个这个新创建对象
  • inout 服务端修改数据同步到客户端对象,可以看作对同一个对象进行修改。

(如果想要更深入理解可以可以参考你真的理解AIDL中的in,out,inout么?

Book实体类

  • 注意:Book.aidl与Book.java包名要要相同,否则编译会保存
// Book.aidl
package com.example.binderdemo;

parcelable Book;
  • Book实体类要实现Parcelable
package com.example.binderdemo;

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

import androidx.annotation.NonNull;

/**
 * Created by Android Studio.
 *
 * @author: linruihang
 * @Date: 2021/10/25
 * @Time: 11:23
 */
public class Book implements Parcelable {
    private String name;

    public Book() {
    }

    public Book(String name) {
        this.name = name;
    }

    protected Book(Parcel in) {
        name = in.readString();
    }

    public static final Creator<Book> CREATOR = new Creator<Book>() {
        @Override
        public Book createFromParcel(Parcel in) {
            return new Book(in);
        }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

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

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeString(this.name);
    }

    public void readFromParcel(Parcel parcel) {
        name = parcel.readString();
    }

    @NonNull
    @Override
    public String toString() {
        return "book name :" + name;
    }
}

2、build project生成java文件

build AIDL文件生成java文件

  • 生成的java文件位置如下图:
    AIDL java文件位置
/*
 * This file is auto-generated.  DO NOT MODIFY.
 */
package com.example.binderdemo;
// Declare any non-default types here with import statements

public interface BookController extends android.os.IInterface
{
  /** Default implementation for BookController. */
  public static class Default implements com.example.binderdemo.BookController
  {
    @Override public java.util.List<com.example.binderdemo.Book> getBookList() throws android.os.RemoteException
    {
      return null;
    }
    @Override public void addBook(com.example.binderdemo.Book book) throws android.os.RemoteException
    {
    }
    @Override public com.example.binderdemo.Book getBook(int pos) throws android.os.RemoteException
    {
      return null;
    }
    @Override
    public android.os.IBinder asBinder() {
      return null;
    }
  }
  /** Local-side IPC implementation stub class. */
  public static abstract class Stub extends android.os.Binder implements com.example.binderdemo.BookController
  {
    private static final java.lang.String DESCRIPTOR = "com.example.binderdemo.BookController";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an com.example.binderdemo.BookController interface,
     * generating a proxy if needed.
     */
    public static com.example.binderdemo.BookController asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.example.binderdemo.BookController))) {
        return ((com.example.binderdemo.BookController)iin);
      }
      return new com.example.binderdemo.BookController.Stub.Proxy(obj);
    }
    @Override public android.os.IBinder asBinder()
    {
      return this;
    }
    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
      java.lang.String descriptor = DESCRIPTOR;
      switch (code)
      {
        case INTERFACE_TRANSACTION:
        {
          reply.writeString(descriptor);
          return true;
        }
        case TRANSACTION_getBookList:
        {
          data.enforceInterface(descriptor);
          java.util.List<com.example.binderdemo.Book> _result = this.getBookList();
          reply.writeNoException();
          reply.writeTypedList(_result);
          return true;
        }
        case TRANSACTION_addBook:
        {
          data.enforceInterface(descriptor);
          com.example.binderdemo.Book _arg0;
          _arg0 = new com.example.binderdemo.Book();
          this.addBook(_arg0);
          reply.writeNoException();
          if ((_arg0!=null)) {
            reply.writeInt(1);
            _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
          }
          else {
            reply.writeInt(0);
          }
          return true;
        }
        case TRANSACTION_getBook:
        {
          data.enforceInterface(descriptor);
          int _arg0;
          _arg0 = data.readInt();
          com.example.binderdemo.Book _result = this.getBook(_arg0);
          reply.writeNoException();
          if ((_result!=null)) {
            reply.writeInt(1);
            _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
          }
          else {
            reply.writeInt(0);
          }
          return true;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }
    private static class Proxy implements com.example.binderdemo.BookController
    {
      private android.os.IBinder mRemote;
      Proxy(android.os.IBinder remote)
      {
        mRemote = remote;
      }
      @Override public android.os.IBinder asBinder()
      {
        return mRemote;
      }
      public java.lang.String getInterfaceDescriptor()
      {
        return DESCRIPTOR;
      }
      @Override public java.util.List<com.example.binderdemo.Book> getBookList() throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        java.util.List<com.example.binderdemo.Book> _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          boolean _status = mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().getBookList();
          }
          _reply.readException();
          _result = _reply.createTypedArrayList(com.example.binderdemo.Book.CREATOR);
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
      @Override public void addBook(com.example.binderdemo.Book book) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          boolean _status = mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().addBook(book);
            return;
          }
          _reply.readException();
          if ((0!=_reply.readInt())) {
            book.readFromParcel(_reply);
          }
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      @Override public com.example.binderdemo.Book getBook(int pos) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        com.example.binderdemo.Book _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          _data.writeInt(pos);
          boolean _status = mRemote.transact(Stub.TRANSACTION_getBook, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().getBook(pos);
          }
          _reply.readException();
          if ((0!=_reply.readInt())) {
            _result = com.example.binderdemo.Book.CREATOR.createFromParcel(_reply);
          }
          else {
            _result = null;
          }
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
      public static com.example.binderdemo.BookController sDefaultImpl;
    }
    static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    static final int TRANSACTION_getBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
    public static boolean setDefaultImpl(com.example.binderdemo.BookController impl) {
      // Only one user of this interface can use this function
      // at a time. This is a heuristic to detect if two different
      // users in the same process use this function.
      if (Stub.Proxy.sDefaultImpl != null) {
        throw new IllegalStateException("setDefaultImpl() called twice");
      }
      if (impl != null) {
        Stub.Proxy.sDefaultImpl = impl;
        return true;
      }
      return false;
    }
    public static com.example.binderdemo.BookController getDefaultImpl() {
      return Stub.Proxy.sDefaultImpl;
    }
  }
  public java.util.List<com.example.binderdemo.Book> getBookList() throws android.os.RemoteException;
  public void addBook(com.example.binderdemo.Book book) throws android.os.RemoteException;
  public com.example.binderdemo.Book getBook(int pos) throws android.os.RemoteException;
}

3、创建AIDL服务

package com.example.binderdemo.service;

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

import androidx.annotation.Nullable;

import com.example.binderdemo.Book;
import com.example.binderdemo.BookController;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Android Studio.
 *
 * @author: linruihang
 * @Date: 2021/10/25
 * @Time: 13:22
 */
public class AidlService extends Service {
    private static final String TAG = "AidlService";
    private List<Book> mBookList;


    @Override
    public void onCreate() {
        super.onCreate();
        initData();
    }

    private void initData() {
        mBookList = new ArrayList<>();
        mBookList.add(new Book("book1"));
        mBookList.add(new Book("book2"));
        mBookList.add(new Book("book3"));
    }

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

    class BookBinder extends BookController.Stub {

        @Override
        public List<Book> getBookList() throws RemoteException {
            Log.d(TAG, "getBookList: " + mBookList.size());
            return mBookList;
        }

        @Override
        public void addBook(Book book) throws RemoteException {
            /**
             *void addBook(out Book book);
             * <p>
             *      参数tag为 out 的情况下,客户端不能向服务端传递数据,参数book相当于 book = new Book();
             *      所以Book必须得有无参构造函数,否则会报错;同时,客户端获取到服务端的数据(如服务端改变书名book.setName("Android开发艺术探索");
             *      服务端能够获取到新的book实例)
             * </p>
             *
             * <p>
             *      参数tag为 in 的情况下,服务端能获取到客户端传递过来的数据,但是客户端通过参数无法感知参数变化,
             *      但是能够通过返回值获取服务端相关的数据
             * </p>
             *
             * <p>
             *     参数为 inout 的情况下,服务端和客户端数据能够双向流动,服务端能够接受客户端传递过来的数据(参数),
             *     客户端也能感知服务端对数据(参数)的更改
             * </p>
             *
             */
            synchronized (this) {
                if (book != null) {
                    mBookList.add(book);
                    //book.setName("Android开发艺术探索");
                    Log.d(TAG, "addBook: " + book.toString());
                } else {
                    Log.e(TAG, "addBook: book is null");
                    Book bookAidl = new Book("aidl");
                    mBookList.add(bookAidl);
                }
            }
        }

        @Override
        public Book getBook(int pos) throws RemoteException {
            synchronized (this) {
                if (pos < 0 || pos >= mBookList.size()) {
                    return null;
                }
                return mBookList.get(pos);
            }
        }
    }


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

Service组件注册(配置process属性,让service与Activity运行在不同的进程)

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

4、编写客户端

  • 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=".MainActivity">

    <Button
        android:id="@+id/btn_add"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/add" />


    <Button
        android:id="@+id/btn_get"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/get" />

    <Button
        android:id="@+id/btn_get_all"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/get_all_book" />

</LinearLayout>
  • Activity作为客户端代码
package com.example.binderdemo;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.media.metrics.LogSessionId;
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.binderdemo.service.AidlService;

import java.util.List;

/**
 * @author linruihang
 */
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = "MainActivity";

    private Button mBtnGet;
    private Button mBtnAdd;
    private Button mBtnGetAll;
    private BookController mBookController;
    private ServiceConnection mServiceConnection;
    private Intent mIntent;

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

        mBtnGet = findViewById(R.id.btn_get);
        mBtnAdd = findViewById(R.id.btn_add);
        mBtnGetAll = findViewById(R.id.btn_get_all);
        mBtnAdd.setOnClickListener(this::onClick);
        mBtnGet.setOnClickListener(this::onClick);
        mBtnGetAll.setOnClickListener(this::onClick);

        bind();
    }

    private void bind() {
        mServiceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                Log.d(TAG, "onServiceConnected======");

                mBookController = BookController.Stub.asInterface(iBinder);
            }

            @Override
            public void onServiceDisconnected(ComponentName componentName) {
                Log.d(TAG, "onServiceDisconnected======");
                mBookController = null;

            }
        };
        mIntent = new Intent(MainActivity.this, AidlService.class);
        bindService(mIntent, mServiceConnection, BIND_AUTO_CREATE);
    }

    @Override
    public void onClick(View view) {
        int id = view.getId();
        if (id == R.id.btn_add) {
            if (mBookController != null) {
                try {
                    Book testBook = new Book("testBook");
                    mBookController.addBook(testBook);
                    Log.d(TAG, "add book result:" + testBook.toString());
                } catch (RemoteException e) {
                    Log.e(TAG, "add book error:" + e.getMessage());
                }
            }
        } else if (id == R.id.btn_get_all) {
            if (mBookController != null) {
                try {
                    List<Book> bookList = mBookController.getBookList();
                    if (bookList != null) {
                        for (Book book : bookList) {
                            Log.d(TAG, book.toString());
                        }
                        Log.d(TAG, "book nun = " + bookList.size());
                    }
                } catch (RemoteException e) {
                    Log.e(TAG, "get book list error:" + e.getMessage());
                }
            }
        } else if (id == R.id.btn_get) {
            try {
                Book book = mBookController.getBook(2);
                if (book != null) {
                    Log.d(TAG, "get book:" + book.toString());
                } else {
                    Log.d(TAG, "get book: null");
                }
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        //解绑定
        if (mServiceConnection != null) {
            unbindService(mServiceConnection);
        }
        if (mIntent != null) {
            stopService(mIntent);
        }
    }
}

需要注意的是在客户端调用这些远程方法时是同步调用,在主线程调用可能会导致ANR,应该在子线程去调用.

5、运行验证

运行验证

  • 服务端成功接收到客户端发送的数据(进程间通信成功)
    通信成功
    本文旨在记录AIDL学习过程,如若文章中涉及的知识点有误,敬请指正!
    完整代码:AIDLDemo
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-10-27 12:56:47  更:2021-10-27 12:58:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 0:37:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码