Android AIDL——进程通信机制详解

Android  AIDL, Android进程机制通信机制,这里就整理下AIDL 的知识,帮助大家学习理解此部分知识!

什么是 AIDL

AIDL 全称 Android Interface Definition Language,即 安卓接口描述语言。听起来很深奥,其实它的本质就是生成进程间通信接口的辅助工具。它的存在形式是一种 .aidl 文件,开发者需要做的就是在该文件中定义进程间通信的接口,编译的时候 IDE 就会根据我们的 .aidl 接口文件生成可供项目使用的 .java 文件,这和我们说的“语法糖”有些类似。

AIDL 的语法就是 java 的语法,就是导包上有点细微差别。java 中如果两个类在相同的包中,是不需要进行导包操作的,但是在 AIDL 中,则必须进行导包声明。

AIDL 详解

构想一个场景:我们有一个图书管理系统,这个系统的通过 CS 模式来实现。具体的管理功能由服务端进程来实现,客户端只需要调用相应的接口就可以。

那么首先定义这个管理系统的 ADIL 接口。

我们在 /rc 新建 aidl 包,包中有三个文件 Book.java 、Book.aidl、IBookManager.aidl 三个文件。

package com.example.aidl book

public class Book implements Parcelable {
 int bookId;
 String bookName;

 public Book(int bookId, String bookName) {
   this.bookId = bookId;
   this.bookName = bookName;
 }

 ...
}

package com.example.aidl;

Parcelable Book;

package com.example.aidl;

import com.example.aidl.Book;

inteface IBookManager {
  List<Book> getBookList();
  void addBook(in Book book);
}

下面对这三个文件分别进行说明:

Book.java 是我们定义的实体类,它实现了 Parcelable 接口,这样 Book 类才能在进程间传输。
Book.aidl 是这个实体类在 AIDL 中的声明。
IBookManager 是服务端和客户端通信的接口。(注意,在 AIDL 接口中除基本类型外,参数前须加方向,in 表示输入型参数,out 表示输出型参数,inout 表示输入输出型参数)

编译器编译后,android studio 为我们的项目自动生成了一个 .java 文件,这个文件包含三个类,这三个类分别是 IBookManager, Stub 和 Proxy,这三个类都是静态类型,我们完全可以把他们分开来,三个类定义如下:

IBookManager


public interface IBookManager extends android.os.IInterface {

  public void addBook(net.bingyan.library.Book book) throws android.os.RemoteException;

  public java.util.List<net.bingyan.library.Book> getBookList() throws android.os.RemoteException;
}

Stub


public static abstract class Stub extends android.os.Binder implements net.bingyan.library.IBookManager {
    private static final java.lang.String DESCRIPTOR = "net.bingyan.library.IBookManager";

    static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    /**
     * Construct the stub at attach it to the interface.
     */
    public Stub() {
      this.attachInterface(this, DESCRIPTOR);
    }

    /**
     * Cast an IBinder object into an net.bingyan.library.IBookManager interface,
     * generating a proxy if needed. http://www.manongjc.com/article/1501.html
     */
    public static net.bingyan.library.IBookManager asInterface(android.os.IBinder obj) {
      if ((obj == null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin != null) && (iin instanceof net.bingyan.library.IBookManager))) {
        return ((net.bingyan.library.IBookManager) iin);
      }
      return new net.bingyan.library.IBookManager.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 {
      switch (code) {
        case INTERFACE_TRANSACTION: {
          reply.writeString(DESCRIPTOR);
          return true;
        }
        case TRANSACTION_addBook: {
          data.enforceInterface(DESCRIPTOR);
          net.bingyan.library.Book _arg0;
          if ((0 != data.readInt())) {
            _arg0 = net.bingyan.library.Book.CREATOR.createFromParcel(data);
          } else {
            _arg0 = null;
          }
          this.addBook(_arg0);
          reply.writeNoException();
          return true;
        }
        case TRANSACTION_getBookList: {
          data.enforceInterface(DESCRIPTOR);
          java.util.List<net.bingyan.library.Book> _result = this.getBookList();
          reply.writeNoException();
          reply.writeTypedList(_result);
          return true;
        }
      }
      return super.onTransact(code, data, reply, flags);
    }
}

Proxy


private static class Proxy implements net.bingyan.library.IBookManager {
      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;
      }

      /**
       * Demonstrates some basic types that you can use as parameters
       * and return values in AIDL.  http://www.manongjc.com/article/1500.html
       */
      @Override
      public void addBook(net.bingyan.library.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);
          if ((book != null)) {
            _data.writeInt(1);
            book.writeToParcel(_data, 0);
          } else {
            _data.writeInt(0);
          }
          mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
          _reply.readException();
        } finally {
          _reply.recycle();
          _data.recycle();
        }
      }

      @Override
      public java.util.List<net.bingyan.library.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<net.bingyan.library.Book> _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
          _reply.readException();
          _result = _reply.createTypedArrayList(net.bingyan.library.Book.CREATOR);
        } finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }
    }

对生成的这三个类的说明如下:

  1. IBookManager 这个类是我们定义的接口,android studio 给它添加了一个父类,让它继承自 android.os.interface 这个接口,这个接口只有一个方法 IBinder asBinder(),这样 IBookManager 中就有三个带实现的方法了,它是服务端进程和客户端进程通信的窗口。
  2. Stub 是个抽象类,这个类继承自 android.os.Binder 类,并且实现的了 IBookManager 这个接口。在 Stub 中,已经实现了 asBinder() 这个接口方法,还有两个是我们定义的 AIDL 接口方法留给继承它的子类去实现。它用在服务端,因此服务端需要实现这两个方法。
  3. Proxy 顾名思义是一个代理类,它是服务端在客户端的一个代理,它也实现了 IBookManager接口,并且实现了 IBookManager 中的所有方法。它用在客户端,是服务端在客户端的代理。现在我们对这三个类逐个分析:
  4. IBookManager 这个类没什么好说的,它只是简单继承了 asInterface 这个接口,作用就是将 IBookManager 转换成 IBinder。
  5. Proxy 这个类上面已经提到过了,它就是进程间通信机制的一个封装类,他的内部实现机制就是 Binder,通过构造方法我们也容易看出来。它的构造方法接受一个 IBinder 类型的参数,参数名为 remote,显然,它代表着服务端。我们看看这个类中的方法 addBook() 和 getBookList():
@Override
public void addBook(net.bingyan.library.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)
      if ((book != null)) {
        _data.writeInt(1);
        book.writeToParcel(_data, 0);
      } else {
        _data.writeInt(0);
      }
      mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
      _reply.readException();
    } finally {
      _reply.recycle();
      _data.recycle();
    }
}
@Override /* http://www.manongjc.com/article/1547.html */
public java.util.List<net.bingyan.library.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<net.bingyan.library.Book> _result;
    try {
       _data.writeInterfaceToken(DESCRIPTOR);
       mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
       _reply.readException();
       _result = _reply.createTypedArrayList(net.bingyan.library.Book.CREATOR);
    } finally {
      _reply.recycle();
      _data.recycle();
    }
    return _result;
}

它们是编译器自动实现的,这两个方法有很多类似之处,可以现在这里透露下:这两个方法就是客户端进程调用服务端进程的窗口。在这两个方法的开始,它们都定义了两个 Parcel(中文译名:包裹)对象。Parcel 这个类我们看上去很眼熟,是的,Book 类中的 writeToParcel() 和 CREATOR中的 createFromParcel() 的参数就是 Parcel 类型的,关于这个类文档中解释如下:

Container for a message (data and object references) that can be sent through an IBinder. A Parcel can contain both flattened data that will be unflattened on the other side of the IPC (using the various methods here for writing specific types, or the general {@link Parcelable} interface), and references to live {@link IBinder} objects that will result in the other side receiving a proxy IBinder connected with the original IBinder in the Parcel.

翻译一下:Proxy 是一个可以通过 IBinder 进行消息传递的一个容器。一个 Parcel 可以包含可序列化的数据,这些数据会在 IPC 的另一端被反序列化;它也可以包含指向 IBinder 对象的引用,这会使得另一端接收到一个 IBinder 类型的代理对象,这个代理对象连接着 Parcel 中的原始 IBinder 对象。

下面用图来直观的说明:

Android 进程通信机制之 AIDL

如图,我们可以很直观的看到服务端以 Parcel 作为数据包裹依靠 Binder 和客户端进行通信。数据包裹就是序列化之后的对象。

如上所述,这两个方法都定义了两个 Parcel 对象,分别叫做 _data 和 _reply,形象的来说,从客户端的角度来看,_data 就是客户端发送给服务端的数据包裹,_reply 服务端发送给客户端的数据包裹。

之后便开始用这两个对象来和服务端进行通信了,我们能够观察到,两个方法中都有这么个方法调用 mRemote.transact(),它有四个参数,第一个参数的意义我们后面再讲,第二个参数 _data 负责向服务端发送数据包裹比如接口方法的参数,第三个参数 _reply 负责从服务端接收数据包裹比如接口方法的返回值。这行代码只有一句简单的方法调用,但是却是 AIDL 通信的最核心部分,它其实进行了一次远程方法调用(客户端通过本地代理 Proxy 暴露的接口方法调用服务端 Stub 同名方法),所以能想到它是一个耗时操作。

在我们的例子中:

1.void addBook(Book book) 需要借助 _data 向服务端发送参数 Book:book,发送的方式就是把 Book 通过其实现的 writeToParcel(Parcel out) 方法打包至 _data 中,正如你能想到的,_data 其实就是参数 out,还记得 Book 中的这个方法的实现吗? 我们是将 Book 的字段一个个打包至 Parcel 中的。

2.List<Book> getBookList() 需要借助 _reply 从服务端接收返回值 List<Book>:books,方法中的做法是将 Book 中的 CREATOR 这个静态字段作为参数传入 _reply 的 createTypedArrayList() 方法中,还记得 Book 中的 CREATOR 吗?当时你是不是好奇这个静态字段应该怎么用呢?现在一切明了了,我们需要靠这个对象(便于理解我们可以叫它”反序列化器“)来对服务端的数据反序列化从而重新生成可序列化的对象或者对象数组。很明显 CREATOR 借助 _reply 生成了 List<Book>:books。

当然这两个方法中的 _data 和 _reply 不仅传递了对象,还传递了一些校验信息,这个我们可以不必深究,但应注意的是,Parcel 打包顺序和解包顺序要严格对应。例如,第一个打包的是 int:i,那么第一解包的也应该是这个整型值。也即打包时第一次调用的如果是 Parcel.writeInt(int),解包时第一次调用的应该是 Parcel.readInt()。

到此,客户端的 Proxy 讲解完了,下面我们看看服务端的 Stub。

Stub 中实现了 IBookManager 的其中一个方法,这个很简单,就是简单的将自身返回,因为 Stub 本身就继承自 Binder,而 Binder 继承自 IBinder,所以没有任何问题。你会问:还有两个方法没实现呢?这两个方法就是我们定义的接口方法,它们留给服务端进程去实现,也就是说,到时候我们在服务端进程中需要定义一个 Stub 的实现者。下面对 Stub 中的两个重要方法进行分析:

IBookManager asInterface(IBinder obj)

public static net.bingyan.library.IBookManager asInterface(android.os.IBinder obj) {
      if ((obj == null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin != null) && (iin instanceof net.bingyan.library.IBookManager))) {
        return ((net.bingyan.library.IBookManager) iin);
      }
      return new net.bingyan.library.IBookManager.Stub.Proxy(obj);
    }

这个方法的作用是将 Stub 类转换成 IBookManager 这个接口,方法中有个判断:如果我们的服务端进程和客户端进程是同一进程,那么就直接将 Stub 类通过类型转换转成 IBookManager;如果不是同一进程,那么就通过代理类 Proxy 将 Stub 转换成 IBookManager。为什么这么做,我们知道如果服务端进程和客户端进程不是同一进程,那么它们的内存就不能共享,就不能通过一般的方式进行通信,但是我们如果自己去实现进程间通信方式,对于普通开发者来说成本太大,因此编译器帮我们生成了一个封装了了进程间通信的工具,也就是这个 Proxy,这个类对底层的进程通信机制进行了封装只同时暴露出接口方法,客户端只需要调用这两个方法实现进程间通信(其实就是方法的远程调用)而不需要了解其中的细节。

有了这个方法,我们在客户端可以借助其将一个 IBinder 类型的变量转换成我们定义的接口 IBookManager,它的使用场景我们会在后面的实例中进行讲解。

onTransact(int code, Parcel data, Parcel reply, int flags)

@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
      switch (code) {
        case INTERFACE_TRANSACTION: {
          reply.writeString(DESCRIPTOR);
          return true;
        }
        case TRANSACTION_addBook: {
          data.enforceInterface(DESCRIPTOR);
          net.bingyan.library.Book _arg0;
          if ((0 != data.readInt())) {
            _arg0 = net.bingyan.library.Book.CREATOR.createFromParcel(data);
          } else {
            _arg0 = null;
          }
          this.addBook(_arg0);
          reply.writeNoException();
          return true; /* http://www.manongjc.com/article/1499.html */
        }
        case TRANSACTION_getBookList: {
          data.enforceInterface(DESCRIPTOR);
          java.util.List<net.bingyan.library.Book> _result = this.getBookList();
          reply.writeNoException();
          reply.writeTypedList(_result);
          return true;
        }
      }
      return super.onTransact(code, data, reply, flags);
}

这个方法我们是不是也很熟悉呢?我们在 Proxy 中也看到一个类似得方法 transact(int, Parcel, Parcel, int),它们的参数一样,而且它们都是 Binder 中的方法,那么它们有什么联系呢?

前面说了,transact() 执行了一个远程调用,如果说 transact() 是远程调用的发起,那么 onTransact() 就是远程调用的响应。真实过程是客户端发器远程方法调用,android 系统通过底层代码对这个调用进行响应和处理,之后回调服务端的 onTransact() 方法,从数据包裹中取出方法参数,交给服务端实现的同名方法调用,最后将返回值打包返回给客户端。

需要注意的是 onTransact() 是在服务端进程的 Binder 线程池中进行的,这就意味着如果我们的要在 onTransact() 方法的中更新 UI,就必须借助 Handler。

这两个方法的第一个参数的含义是 AIDL 接口方法的标识码,在 Stub 中,定义了两个常量作为这两个方法的标示:

static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
   static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);

如果 code == TRANSACTION_addBook,那么说明客户端调用的是 addBook();如果 code == TRANSACTION_getBookList,那么客户端调用的是 getBookList(),然后交由相应的服务端方法处理。 用一张图来表示整个通信过程:

Android 进程通信机制之 AIDL

了解了 AIDL 的整个过程,接下来就是 AIDL 在安卓程序中的应用了。

 AIDL 的使用

相信大家应该都和清楚 Service 的使用了吧,Service 虽然称作“服务”,并且运行于后台,但是它们默认还是运行在默认进程的主线程中。其实让 Service 运行在默认进程中,有点大材小用了。android 的很多系统服务都运行于单独的进程中,供其他应用调用,比如窗口管理服务。这样做的好处是可以多个应用共享同一个服务,节约了资源,也便于集中管理各个客户端,要注意问题的就是线程安全问题。

那么接下来我们就用 AIDL 实现一个简单的 CS 架构的图书管理系统。

首先我们定义服务端:

BookManagerService


public class BookManagerService extends Service {

  private final List<Book> mLibrary = new ArrayList<>();

  private IBookManager mBookManager = new IBookManager.Stub() {
    @Override
    public void addBook(Book book) throws RemoteException {
      synchronized (mLibrary) {
        mLibrary.add(book);
        Log.d("BookManagerService", "now our library has " + mLibrary.size() + " books");
      }

    }

    @Override
    public List<Book> getBookList() throws RemoteException {
      return mLibrary;
    }
  };

  @Override /* http://www.manongjc.com/article/1496.html */
  public IBinder onBind(Intent intent) {
    return mBookManager.asBinder();
  }

}

<service
   android:process=":remote"
   android:name=".BookManagerService"/>

服务端我们定义了 BookManagerService 这个类,在它里面我们创建了服务端的 Stub 对象,并且实现了需要实现的两个 AIDL 接口方法来定义服务端的图书管理策略。在 onBind() 方法中我们将 IBookManager 对象作为 IBinder 返回。我们知道,当我们绑定一个服务时,系统会调用 onBinder() 方法得到服务端的 IBinder 对象,并将其转换成客户端的 IBinder 对象传给客户端,虽然服务端的 IBinder 和 客户端的 IBinder 是两个 IBinder 对象,但他们在底层都是同一个对象。我们在 xml 中注册 Service 时给它指定了进程名,这样 Service 就能运行在单独的进程中了。

接下来看看客户端的实现:

Client


public class Client extends AppCompatActivity {

  private TextView textView;

  private IBookManager bookManager;

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

    Intent i = new Intent(Client.this, BookManagerService.class);
    bindService(i, conn, BIND_AUTO_CREATE);

    Button addABook = (Button) findViewById(R.id.button);
    addABook.setOnClickListener(v -> {
      if (bookManager == null) return;
      try {
        bookManager.addBook(new Book(0, "book"));
        textView.setText(getString(R.string.book_management_system_book_count, String.valueOf(bookManager.getBookList().size())));
      } catch (RemoteException e) {
        e.printStackTrace();
      }

    });

    textView = (TextView) findViewById(R.id.textView);
  }

  private ServiceConnection conn = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
      Log.d("Client -->", service.toString());

      bookManager = IBookManager.Stub.asInterface(service);
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
      Log.d("Client", name.toString());
    }
  };

}

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical" android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:weightSum="1"
  android:gravity="center">

  <Button
    android:text="http://www.manongjc.com/article/1495.html"
    android:layout_width="111dp"
    android:layout_height="wrap_content"
    android:id="@+id/button" />

  <TextView
    android:layout_marginTop="10dp"
    android:text="@string/book_management_system_book_count"
    android:layout_width="231dp"
    android:gravity="center"
    android:layout_height="wrap_content"
    android:id="@+id/textView" />
</LinearLayout>

我们的客户端就是一个 Activity,onCreate() 中进行了服务的绑定,bindService() 方法中有一参数 ServiceConnection:conn,因为绑定服务是异步进行的,这个参数的作用就是绑定服务成功后回调的接口,它有两个回调方法:一个是连接服务成功后回调,另一个在与服务端断开连接后回调。我们现在关心的主要是 onServiceConnected() 方法,在这里我们只做了一件事:将服务端转换过来的 IBinder 对象转换成 AIDL 接口,我们定义 IBookManager:bookManager 字段来保持对其的引用。这样的话,我们就可以通过这个 bookManager 来进行方法的远程调用。我们给客户端的 Button 注册事件:每一次点击都会向服务端增加一本书,并且将图书馆现有的图书数量显示出来。

现在我们看看程序的运行效果:

每当我们点击按钮,我们就成功的向服务端添加了一本书,说明我们通过 AIDL 跨进程通信成功了。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

(0)

相关推荐

  • Android 使用【AIDL】调用外部服务的解决方法

    在Android 中有一种服务说是服务其实倒不如说是一个接口,这个接口名为:Android Interface Definition Language ,这个接口可提供跨进程访问服务,英文缩写为:AIDL. 此种服务的好处在于,多个应用程序之间建立共同的服务机制,通过AIDL在不同应用程序之间达到数据的共享和数据相互操作,下面将通过一个DEMO 演示AIDL 是如何为应用程序之间提供服务的.本文大纲为:•1.创建AIDL 服务端.•2.创建AIDL 客户端.•3.客户端调用服务端提供的服务接口.

  • Android 进程间通信AIDL使用详解

    一.概述 AIDL 意思即 Android Interface Definition Language,翻译过来就是Android接口定义语言,是用于定义服务器和客户端通信接口的一种描述语言,可以拿来生成用于IPC的代码.从某种意义上说AIDL其实是一个模板,因为在使用过程中,实际起作用的并不是AIDL文件,而是据此而生成的一个IInterface的实例代码,AIDL其实是为了避免我们重复编写代码而出现的一个模板 设计AIDL这门语言的目的就是为了实现进程间通信.在Android系统中,每个进程

  • Android中如何利用AIDL机制调用远程服务

    在Android中,每个应用程序都有自己的进程,当需要在不同的进程之间传递对象时,该如何实现呢?显然, Java中是不支持跨进程内存共享的.因此要传递对象,需要把对象解析成操作系统能够理解的数据格式,以达到跨界对象访问的目的.在JavaEE中,采用RMI通过序列化传递对象.在Android中,则采用AIDL(Android Interface DefinitionLanguage:接口描述语言)方式实现. AIDL是一种接口定义语言,用于约束两个进程间的通讯规则,供编译器生成代码,实现Andro

  • Android编程实现AIDL(跨进程通信)的方法详解

    本文实例讲述了Android编程实现AIDL(跨进程通信)的方法.分享给大家供大家参考,具体如下: 一. 概述: 跨进程通信(AIDL),主要实现进程(应用)间数据共享功能. 二. 实现流程: 1. 服务器端实现: (1)目录结构,如下图: (2)实现*.aidl文件: A. IAIDLService.aidl实现: package com.focus.aidl; import com.focus.aidl.Person; interface IAIDLService { String getN

  • 基于Android AIDL进程间通信接口使用介绍

    AIDL:Android Interface Definition Language,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口. ICP:Interprocess Communication ,内部进程通信. 使用: 1.先创建一个aidl文件,aidl文件的定义和java代码类似,但是!它可以引用其它aidl文件中定义的接口和类,但是不能引用自定义的java类文件中定义的接口和类,要引用自定义的接口或类,需要为此类也定义一个对应的aidl文件,并且此

  • 实例讲解Android中的AIDL内部进程通信接口使用

    首先描述下我们想要实现的内容,我们希望在一个应用中通过点击按钮,去操作另一个进程中应用的音乐播放功能. 如图,我们点击"播放"时,系统就会去远程调用我们提供的一个service(与当前service不是同一个应用哦),然后操作service中的音乐播放,点击"停止"则会终止播放.想要重新播放的话,必须先点"销毁service",再点播放按钮哦.(至于这里为什么要先点销毁按钮才能播放,完全是为了给大家展示下,远程调用service时,怎么去解绑se

  • 浅谈Android Aidl 通讯机制

    服务端: 首先是编写一个aidl文件,注意AIDL只支持方法,不能定义静态成员,并且方法也不能有类似public等的修饰符:AIDL运行方法有任何类型的参数和返回值,在java的类型中,以下的类型使用时不需要导入包(import),基本数据类型.String.Map.List.当然为了避免出错,建议只要使用了,就导入包. 然后在服务端启动一个服务并注册,编写一个任意类实现AIDL文件生成的JAVA接口Stub! 最后在service里面实例化你的任意类并且在onBind(Intent a)方法上

  • Android AIDL和远程Service调用示例代码

    Android:AIDL和远程Service调用 本讲的内容,理解起来很难,也许你看了很多资料也看不明白,但是用起来缺简单的要命.所以我们干脆拿一个音乐播放器中进度条的实例来说明一下AIDL和Remote Service的价值和使用方法,你把这个例子跑一边,体会一下就OK了.下面的例子是我 正在准备的项目实例中的一部分. 首先说明一下我们面临的问题,如果看不懂下面的描述请看前面的课程: 第一.我们知道在AndroId中如果需要进行音乐播放,最方面的方法就是使用自带的MediaPlayer对象,如

  • Android AIDL——进程通信机制详解

    Android  AIDL, Android进程机制通信机制,这里就整理下AIDL 的知识,帮助大家学习理解此部分知识! 什么是 AIDL AIDL 全称 Android Interface Definition Language,即 安卓接口描述语言.听起来很深奥,其实它的本质就是生成进程间通信接口的辅助工具.它的存在形式是一种 .aidl 文件,开发者需要做的就是在该文件中定义进程间通信的接口,编译的时候 IDE 就会根据我们的 .aidl 接口文件生成可供项目使用的 .java 文件,这和

  • Android  AIDL——进程通信机制详解

    Android  AIDL, Android进程机制通信机制,这里就整理下AIDL 的知识,帮助大家学习理解此部分知识! 什么是 AIDL AIDL 全称 Android Interface Definition Language,即 安卓接口描述语言.听起来很深奥,其实它的本质就是生成进程间通信接口的辅助工具.它的存在形式是一种 .aidl 文件,开发者需要做的就是在该文件中定义进程间通信的接口,编译的时候 IDE 就会根据我们的 .aidl 接口文件生成可供项目使用的 .java 文件,这和

  • Android中的binder机制详解

    前言 Binder做为Android中核心机制,对于理解Android系统是必不可少的,关于binder的文章也有很多,但是每次看总感觉看的不是很懂,到底什么才是binder机制?为什么要使用binder机制?binder机制又是怎样运行的呢?这些问题只是了解binder机制是不够的,需要从Android的整体系统出发来分析,在我找了很多资料后,真正的弄懂了binder机制,相信看完这篇文章大家也可以弄懂binder机制. 1.Binder是什么? 要理解binder,先要知道IPC,Inter

  • Android 跨进程SharedPreferences异常详解

    Android 跨进程SharedPreferences异常详解 Context c = null; try { c = context.createPackageContext(PREFERENCE_PACKAGE, Context.CONTEXT_IGNORE_SECURITY); } catch (NameNotFoundException e) { e.printStackTrace(); } if (c != null) { SharedPreferences infoSp = c.g

  • C#使用命名管道Pipe进行进程通信实例详解

    1.新建解决方案NamedPipeExample 新建两个项目:Client和Server,两者的输出类型均为"Windows 应用程序".整个程序的结构如下图所示. 此Form1为Client的窗体,如下图所示. 后端代码,如下. using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using Syst

  • Python并发编程线程消息通信机制详解

    目录 1 Event事件 2 Condition 3 Queue队列 4 总结一下 前面我已经向大家介绍了,如何使用创建线程,启动线程.相信大家都会有这样一个想法,线程无非就是创建一下,然后再start()下,实在是太简单了. 可是要知道,在真实的项目中,实际场景可要我们举的例子要复杂的多得多,不同线程的执行可能是有顺序的,或者说他们的执行是有条件的,是要受控制的.如果仅仅依靠前面学的那点浅薄的知识,是远远不够的. 那今天,我们就来探讨一下如何控制线程的触发执行. 要实现对多个线程进行控制,其实

  • PHP-FPM和Nginx的通信机制详解

    PHP-FPM 介绍 CGI 协议与 FastCGI 协议 每种动态语言( PHP,Python 等)的代码文件需要通过对应的解析器才能被服务器识别,而 CGI 协议就是用来使解释器与服务器可以互相通信.PHP 文件在服务器上的解析需要用到 PHP 解释器,再加上对应的 CGI 协议,从而使服务器可以解析到 PHP 文件. 由于 CGI 的机制是每处理一个请求需要 fork 一个 CGI 进程,请求结束再kill掉这个进程,在实际应用上比较浪费资源,于是就出现了CGI 的改良版本 FastCGI

  • Android View 事件分发机制详解

    Android开发,触控无处不在.对于一些 不咋看源码的同学来说,多少对这块都会有一些疑惑.View事件的分发机制,不仅在做业务需求中会碰到这些问题,在一些面试笔试题中也常有人问,可谓是老生常谈了.我以前也看过很多人写的这方面的文章,不是说的太啰嗦就是太模糊,还有一些在细节上写的也有争议,故再次重新整理一下这块内容,十分钟让你搞明白View事件的分发机制. 说白了这些触控的事件分发机制就是弄清楚三个方法,dispatchTouchEvent(),OnInterceptTouchEvent(),o

  • Android结束进程的方法详解

    本文实例讲述了Android结束进程的方法.分享给大家供大家参考,具体如下: 最近在做一个类似与任务管理器的东西,里面有个功能,可以通过这个管理器结束掉其他的进程. 在Android平台下,结束进程的方法还是比较多的.首先指明,此处的"结束进程",包含了结束自身进程和结束其他进程两个方面.通过查阅SDK文档和网上的一些资料,自己找到一些结束进程的方法.在这里做一些归纳和总结,文章的部分信息有可能来自网上已有的文章和帖子,由于过了比较长时间,所以若发现本文与其他文章雷同,请谅解. 一.结

  • Android事件的分发机制详解

    在分析Android事件分发机制前,明确android的两大基础控件类型:View和ViewGroup.View即普通的控件,没有子布局的,如Button.TextView. ViewGroup继承自View,表示可以有子控件,如Linearlayout.Listview这些.今天我们先来了解View的事件分发机制. 先看下代码,非常简单,只有一个Button,分别给它注册了OnClick和OnTouch的点击事件. btn.setOnClickListener(new View.OnClick

随机推荐