[컴][안드로이드] aidl 사용하기, 동작 흐름

service 에서 activity 로 message 전송 / aidl / service 와 activity 간 통신 / 서비스와 액티비티 통신



AIDL 사용법

여기서는 대략적인 사용법만 이야기 하겠다. 자세한 사항은 sdk 에 있는 예제 코드를 확인하도록 하자.

그리고 이 예제는 내가 test 한 예제이다.


Example Files Paths

  • <sdk_path>\samples\android-17\ApiDemos\src\com\example\android\apis\app\IRemoteService.aidl
  • <sdk_path>\samples\android-17\ApiDemos\src\com\example\android\apis\app\IRemoteServiceCallback.aidl
  • <sdk_path>\samples\android-17\ApiDemos\src\com\example\android\apis\app\ISecondary.aidl
  • <sdk_path>\samples\android-17\ApiDemos\src\com\example\android\apis\app\RemoteService.java


동작

동작은 Messenger 로 통신하는 것과 다를 바 없다. 그래서 "Messenger 개념 및 사용법"를 참고하는 것도 도움이 될 것이다.

여기서 activity 와 service 사이의 통신을 가능하도록 하기 위해서 아래와 같은 작업이 필요하다.

  • activity 에게 service 의 reference 를 줘야하고,
  • service 에게는 activity 의 handler 를 넘겨 줘야한다.

이것은 코드에서 다음과 같이 처리되었다.

  • activity.handler 는 onServiceConnected 에서 service 로 전달되고,(mService.registerCallback())
  • service의 reference 는 bindService 를 통해서 처리할 수 있다.



이제 좀 더 구체적으로 살펴보자.

aidl 로 IRemoteService 라는 interface 를 정의했다고 가정하자.

inteface 를 aidl 에 정의해 놓고 compile 을 하면

  • inteface -> abstract interface
  • static abstract class Stub extends Binder implements IRemoteService

가 생긴다.(아래 코드 참조)

그 이후는 일반적으로 service 를 bind 하고 사용하는 모습과 같다.

bindService 부터 mCallback 이 호출되는 모습을 대략적으로 그려봤다. 대략 요약하면

  1. Service 에 interface 로 register 를 만들고,
  2. 서비스가 connected 되면(onServiceConectted), register 를 통해서 Activity 에 있는 함수(callback) 를 Service 에 등록 해 놓는다.
  3. 그리고 나중에 Service 에서 필요할 때 호출한다.
  4. 그리고 Activity 에서 호출되는 함수(callback) 는 handler 를 이용해서 msg 를 처리한다.(그렇지 않으면, 동기화에 문제가 있을 수 있다.)

아래 그림은 "새창에서 열기" 로 열어야 크게 볼 수 있다.




IRemoteService.aidl >> IRemoteService.class
package com.example.samples.mp3playerremote;

import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;

public abstract interface IRemoteService extends IInterface
{
  public abstract void registerCallback(IRemoteServiceCallback paramIRemoteServiceCallback)
    throws RemoteException;

  public abstract void unregisterCallback(IRemoteServiceCallback paramIRemoteServiceCallback)
    throws RemoteException;

  public static abstract class Stub extends Binder
    implements IRemoteService
  {
    private static final String DESCRIPTOR = "com.example.samples.mp3playerremote.IRemoteService";
    static final int TRANSACTION_registerCallback = 1;
    static final int TRANSACTION_unregisterCallback = 2;

    public Stub()
    {
      attachInterface(this, "com.example.samples.mp3playerremote.IRemoteService");
    }

    public static IRemoteService asInterface(IBinder obj)
    {
      if (obj == null) {
        return null;
      }
      IInterface iin = obj.queryLocalInterface("com.example.samples.mp3playerremote.IRemoteService");
      if ((iin != null) && ((iin instanceof IRemoteService))) {
        return (IRemoteService)iin;
      }
      return new Proxy(obj);
    }

    public IBinder asBinder() {
      return this;
    }

    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
      switch (code)
      {
      case 1598968902:
        reply.writeString("com.example.samples.mp3playerremote.IRemoteService");
        return true;
      case 1:
        data.enforceInterface("com.example.samples.mp3playerremote.IRemoteService");

        IRemoteServiceCallback _arg0 = IRemoteServiceCallback.Stub.asInterface(data.readStrongBinder());
        registerCallback(_arg0);
        reply.writeNoException();
        return true;
      case 2:
        data.enforceInterface("com.example.samples.mp3playerremote.IRemoteService");

        IRemoteServiceCallback _arg0 = IRemoteServiceCallback.Stub.asInterface(data.readStrongBinder());
        unregisterCallback(_arg0);
        reply.writeNoException();
        return true;
      }

      return super.onTransact(code, data, reply, flags);
    }

    private static class Proxy implements IRemoteService {
      private IBinder mRemote;

      Proxy(IBinder remote) {
        this.mRemote = remote;
      }

      public IBinder asBinder() {
        return this.mRemote;
      }

      public String getInterfaceDescriptor() {
        return "com.example.samples.mp3playerremote.IRemoteService";
      }

      public void registerCallback(IRemoteServiceCallback cb)
        throws RemoteException
      {
        Parcel _data = Parcel.obtain();
        Parcel _reply = Parcel.obtain();
        try {
          _data.writeInterfaceToken("com.example.samples.mp3playerremote.IRemoteService");
          _data.writeStrongBinder(cb != null ? cb.asBinder() : null);
          this.mRemote.transact(1, _data, _reply, 0);
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }

      public void unregisterCallback(IRemoteServiceCallback cb)
        throws RemoteException
      {
        Parcel _data = Parcel.obtain();
        Parcel _reply = Parcel.obtain();
        try {
          _data.writeInterfaceToken("com.example.samples.mp3playerremote.IRemoteService");
          _data.writeStrongBinder(cb != null ? cb.asBinder() : null);
          this.mRemote.transact(2, _data, _reply, 0);
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
    }
  }
}


AIDL in intelliJ

http://stackoverflow.com/questions/15673319/android-intellij-idea-12-aidl
android-idl-compiler 가 따로 compile 을 해준다. 하지만 syntax 에 대한 검사를 미리 해주지 않기 때문에, syntax 를 잘 체크해야 한다.




See Also

  1. http://javaexpert.tistory.com/114



댓글 없음:

댓글 쓰기