«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

올해는 머신러닝이다.

[펌]안드로이드 aidl 시작하기 본문

Android/Tip&Tech

[펌]안드로이드 aidl 시작하기

행복한 수지아빠 2010. 12. 7. 11:38

필요성을 느낄때 : Activity에서 Service를 바인딩 한후 Activity에서 서비스 메소드는 간단히 호출되지만..


Service에서 Activity 메소드를 호출하는 건 힘들다는 걸 느꼈다..


그래서 공부한게 이 방법인 것 같다.^^;


출처 : 

http://blog.naver.com/dlgusrb5061?Redirect=Log&logNo=120101130132


아래의 설명은 안드로이드 프로그래밍을 기본적으로 한다고 생각하고 쓴다

 

1. 기본적으로 안드로이드 프로젝트를 생성한다.

 

2. 액티비티 에서 생성할 서비스 클래스를 만든다

 

3. .aidl 파일을 만든다

package com.service;                     // 패키지 이름 따라서..

 

interface state{                               // state 라는 인터페이스를 만든다  파일명도 state.aidl

         int getState();                        // 값을 주기 위한 함수
         int setState(int k);                  // 값을 입력하기 위한 함수

}

 

4. 위의 인터페이스를 이용하여 서비스에 bind를 생성한다.   Stub를 이용하여 만들수 있다.

// state.Stub 클래스

private final state.Stub binder = new state.Stub() {
           @Override
           public int getState() throws RemoteException {   
                      return 0;

           }
  
           @Override
           public int setState(int k) throws RemoteException {
                      return 0;
            }

};

 

synchronized private int getStatePageImpl() {
           return 0;

}

 

5. 서비스 클래스 에서 onBind함수의 return을 위의 binder로 해 준다

@Override
public IBinder onBind(Intent intent) {
           return binder;
}

 

6. 액티비티 클래스 에서 ServiceConnection 을 이용하여 서비스가 시작될 때와 종료될 때 상황을 구현한다

 

import android.content.ServiceConnection;

 

private ServiceConnection serviceConn = new ServiceConnection() {
     public void onServiceConnected(ComponentName className, IBinder binder) {
            service = state.Stub.asInterface(binder);
     }

 

     public void onServiceDisconnected(ComponentName className) {
            

     }

};

 

7. 서비스 시작과 종료를 구현한다

 

<시작>

serviceintent = new Intent(this, mainService.class);
bindService(serviceintent, serviceConn, BIND_AUTO_CREATE);

 

<종료>

unbindService(serviceConn);


==========================자세한 설명


AIDL를 사용하여 원격 언터페이스를 사용하거나 설계(디자인)하기   - 번역 2008년 2월 20일 김문섭 (Easygn Institute)


그 동안 각각의 어플리케이션은 자신이 해당되는 프로세스에서 실행되며, 다른 프로세스가 실행시되는
응용프로그램 인터페이스나 프로세스 사이에 개체를 전달해야 할 경우에 당신은 서비스를 쓰기가 가능합니다.
기본 적으로 안드로이드 플랫폼 상에서 한 프로세스는 메모리상에서, 다른 프로세스에 대한 정상적인 액세스가 불가능합니다. 
한마디로, 그들은 오브젝트 안에서 운영체제 시스템이 이해할 수 있도록 세분화된 개체를 필요로 합니다,
그리고 오브젝트 간의 구획화 작업을 당신이 하도록 합니다.

그 코드를 구획화 하는 작업은 골치아픈 작업이고, 그래서 우리는 당신을 위해 AIDL 도구를 제공하게 되었습니다.

AIDL (안드로이드 인터페이스 정의 언어)는 하나의 안드로이드 장치 위에서 잠김프로세스 통신규약(IPC)에 의해 
두 프로세스들 사이에 대화가 가능하도록 하기위한 목적으로 생성되어진 코드를 사용할 수 있게하는 IDL 언어 입니다. 


만약 당신이 한 프로세스(예: Acitivity객체) 안의 코드가 
또 다른 프로세스(예: Service 객체) 안의 한 오브젝트 위의것을 필요로 하게 된다면 
당신은 AIDL 을 사용하여 구획화 파라미터들의 코드를 생성하게 될 것입니다.


그 AIDL IPC 메커니즘은 COM or Corba 와 유사한 인터페이스를 기반으로 하고 있습니다.
그러나 보다 가볍고 빠르게 만들어졌습니다.
이것은 한 프록시 클래스와 클라이언트 클라이언트 사이에 값을 넘길 수 있도록 구현하는데 사용되어 집니다.


이 페이지는 다음의 주요 단원으로 나눠졌습니다:

* AIDL를 사용하여 IPC를 구현합니다. 
* .aidl 포맷의 IPC Class 를 호출해 봅니다.

 


◎ AIDL 를 통해 IPC 구현하기


AIDL를 사용하여 IPC 서비스를 구현하는 순서는 다음과 같습니다.

1. 내 .aidl 파일을 작성하기 
   - 이 파일은 미리 정의된 메소드와 필드를 클라이언트에 사용할 수 있도록 
     인터페이스(내인터페이스.aidl)를 정의합니다.

2. 내가 만든 .aidl 파일을 추가하기
   - (당신에 의해 이클립스 플러그인이 관리하도록 합니다) 컴파일러로 안드로이드에 인클루드 하고
     AIDL를 호출하고, tool/ 안에 넣습니다.

3. 내 인터페이스 메소드를 구현하기
   - AIDL 컴파일러는 당신의 AIDL 인터페이스로부터 자바프로그래밍 언어로 구현된 것을 생성합니다.
     이 인터페이스는 한 인터페이스(그리고 IPC 호출를 위해 필수적인 약간의 메소드가 추가된)를 상속한
     하나의 추상화 클래스로 명명된 조각을 가집니다.

4. 내 인터페이스를 클라이언트에 통보하기 
   - 만약 당신이 서비스에 기재한다면, 한 당신이 구현된 인터페이스 클래스의 인스턴스를 
     Service 로 확장 오버라이드된 Service.onBind(Intent) 에게 반환할 것입니다.


● .aidl 파일 작성하기

AIDL 은 하나 이상의 메소드를 함께 사용하는 인터페이스를 당신이 선언한 수 있도록 간단한 문법을 쓰며,
패러미터나 반환값을 가질 수 있습니다. 그 패러미터들과 반환값은 다양한 타입이 될 수 있으며,
심지어는 AIDL로 생성된 인터페이스도 될 수 있습니다.
그러나 이 점을 중요하게 참고해야 합니다. 생성되지 않은 모든 타입,
심지어 만약 같은 패키지에 정의된 당신의 인터페이스를 포함해서 당신은 반드시 import 해야 합니다. 
여기에 AIDL 가 자체 지원할 수 있는 데이터 타입이 있습니다.


* 원시형태의 자바 프로그래밍 언어타입(int, boolean 기타) - import 명시가 필요하지 않습니다.)
* 다음에 해당되는 클래스(import 명시가 필요치 않습니다.)
  String

  List   - List 내부의 모든 엘리먼트는 반드시 하나의 이 아래에 있는 리스트 내부의 한 속성이어야 합니다.
           다른 AIDL로 생성된 인터페이스와 세부 가능화된 것들을 인클루드 합니다. 리스트는 제네릭 클래스 (예: List<String>)를
           사용하는 방법을 써도 됩니다.   다른 측면의 현실적이고 구체적인 클래스라면, 비록 메소드는 리스트 인터페이스를 사용하여 
           생성된 것일지라도, 항상 ArrayList 를 통해 받을 수 있도록 하는 것입니다,

  Map    - 맵 객체 안의 모든 엘리먼트들은 반드시 리스트 안에있는 하나 이상의 속성들 이어야 하며,
           다른 AIDL로 생성된 인터페이스와 세부 가능화된 것들을 인클루드 합니다.
           제너릭 맵 (예: Map(String, Integer)은 지원하지 않습니다. 다른 측면의 현실적이고 구체적인 클래스라면, 
           비록 메소드는 맵 인터페이스를 사용해 생성된 것일지라도 항상 해쉬맵을 통해 받는 것입니다.

  CharSeq- TextView 나 다른 위젯 오브젝트들로 CharSequence 속성들을 사용하기에 매우 유용합니다.
  uence

  다른 AIDL 생성된 인터페이스는 언제나 레퍼런스로 통과됩니다. import 를 명시하는 방법은 아래와 같습니다.
   사용자 정의를 구현 클래스는 세분화가능한 프로토콜을 하거나 값 별로 전달합니다.  import를 명시하는 방법은 아래와 같습니다.

  여기 기본 AIDL 문법이 있습니다 - [ 문서 내의 소스코드 참조]

 

● 인터페이스 구현

AIDL는 당신과 함께 비슷한 이름을 가진 당신의 .aidl file 를 위해 인터페이스 파일을 생성합니다
만약 당신이 이클립스 플러그인을 사용한다면 AIDL은 빌드 프로세스(프로젝트 빌드를 위해 미리 AIDL을 실행시킬 필요가 없습니다)
파트에 자동으로 실행되도록 합니다.
만약 이 플러그인을 쓰게되면 당신은 AIDL을 먼저 실행하게 될 것입니다.

생성된 인터페이스를 포함하여 한 추상화 내부 클래스 명명 조각에 모든 당신이 선언한 .aidl 파일 그 메소드를을 선언합니다.
조각은 또한 약간의 헬퍼 메소드, 그 중에 가장 많은 asInterface(), 어느 곳에 가져온 IBinder ( application.Context.bindService()가
성공했을 때의 클라이언트 onServiceConnected() 구현체 ), 그리고 IPC메소드를 호출하는데 사용된 인터페이스의 인스턴스의 리턴 값 
들로 선언되어 있습니다. Calling an IPC 섹션을 참고하면 좀더 캐스트하는 것에 대한 더 많은 사항을 알 수 있습니다.

당신의 인터페이스를 구현할 때, YourInterface.Stub 를 확장(상속), 그리고 메소드를 구현 (.aidl 파일과 stub 구현 메소드를
안드로이드 빌드프로세스 가 .Java 파일을 프로세스하기 전에 먼저 만들도록 할 수 있습니다. )

여기 간단한 IRemoteService 호출에 대한 인터페이스 구현 예제가 있으며, 단일 메소드로 분리되고
getPid 를 사용한 익명의 인스턴스의 경우입니다. (참고할 것):

// No need to import IRemoteService if it's in the same project.
private final IRemoteService.Stub mBinder = new IRemoteService.Stub(){
    public int getPid(){
        return Process.myPid();
    }
}

 

● 인터페이스 구현에는 몇 가지 규칙이 있습니다.

* 당신의 호출 전송에 대하여 미리 예외검사를 하지 않습니다.
* IPC는 동시에 호출 됩니다. 만약 당신이 IPC 서비스가 보다 많은 작은 밀리초 단위로 처리해나갈 필요가 있다고 느끼면 
 알고 있다면, 당신은 되도록 Acitivity/View 쓰레드를 호출하지 말아야 하는데, 그 이유는 CPU가 특정 어플리케이션(안드로이드는  "Application not Responding" 다이얼로그를 표시할 수도 있습니다)에 매달려 정체될 될 수도 있기 입니다.
 다른 쓰레드로 나눠서 처리하는 방법을 시도해 봅니다.
* 메소드들은 이렇게만 지원됩니다 " 당신은 static 필드 형태로 AIDL 인터페이스를 선언할 수 없습니다.

 


● 인터페이스를 클라이언트에 공개하기

 이제 당신은 인터페이스 구현법을 알게 되었고 클라이언트에 공개할 차례 입니다. 당신의 서비스에 발표 한단 뜻이기도 합니다.
 Service를 상속받고 Service.onBind(Intent) 를 구현하도록 받아서 구현된 인터페이스 클래스 의 인스턴스를 반환합니다.

 여기 IRemoteService 인터페이스를 클라이언트 공개하는 일부 코드가 있습니다. (문서 소스코드 참조)

 


● 패러미터 값을 Parcelables(꾸러미객체) 를 이용해서 인수값으로 넘겨주기
 
 주의 :
   Parcelables 는 현재 당신이 이클립스 플러그인을 사용할시에 작동하지 않습니다. 
   강제로 시도할 경우 다음과 같은 에러들을 보게 될 것입니다. :
    .aidl files that only declare parcelables don't need to go in the makefile
     aidl can only generate code for interface, not parcelables
  이것으로 한계가 있음을 알게 되었습니다. Parcelable은 역시 build.xml 파일들 이나 당신이 가진
  사용자정의 빌드 시스템만을 사용할 수 있습니다.
  작업공간은 당신은 위해 aidl tool 로 손안의 모든 인터페이스를 구현하고 추가할 수 있도록 
  당신의 이클립스 프로젝트 상에서 실행되어 집니다.
  왜 이클립스가 aidl 파일 컴파일 시도가 불가능한지를 5장을 통해 알아보세요.
 

  만약 당신이 만든 클래스가 한 프로세스 가 다른 AIDL 인터페이스를 경유하여 보내게 되는 일을 수행한다면, 그일도 가능합니다.
  당신은 당신의 클래스가 다른 측면의 IPC 에게도 유효하다면. 그 코드를 안전하게 보호해야 합니다.
  일반적으로 그것은 당신이 시작과 동시에 서비스와 의사소통을 할 수 있음을 의미합니다.

  여기에 5개 파티의 Parcelable 프로토콜을 지원하는 클래스 생성법이 있습니다.

  1. Parcelable 인터페이스로 당신의 클래스를 구현하세요.
  2. public void writeToParcel(Parcel out) : 오브젝트와 꾸러미에 쓰기의 현재 상태를 보존할 수 있도록  다음과 같이 구현하세요.
  3. public void readToParcel(Parcel in) : 오브젝트로부터 꾸러미 값을 읽을 수 있도록 다음과 같이 구현합니다.
  4. CREATOR를 호출할 static 필드를 추가합니다. 당신의 클래스에 이것은 Parcelable.Create 인터페이스로 구현할 수 있습니다.
  5. 마지막이지만 남은 것이 있습니다. aidl 파일을 AIDL 도구가 찾을 수 있도록 parcelable 클래스에 추가하되,
     하지만 당신의 빌드에 추가하지 마세요. 이것은 C 헤더파일을 쓰는 것과 비슷합니다.
     당신은 aidl을 컴파일할 수 없습니다. parcelable 로 하여금 마치 헤더파일을 기본적으로 컴파일할수 없는 것 처럼 말입니다.

  AIDL 는 이 메소드와 필드를 당신의 오브젝트들의 구획화와 비구획화 된 곳에 생성할 것입니다.

  여기에 Rect 클래스를 Parcelable 프로토콜을 통해 구현한 예제가 있습니다.  (문서 코드 참조)

 
  Rect.aidl 예제가 있습니다.
  package android.graphics;

  // Declare Rect so AIDL can find it and knows that it implements
  // the parcelable protocol.
  parcelable Rect;

 
  구획화하는 예쁘고 간단한 Rect 클래스 입니다. 다른 메소드에서 당신이 꾸러미에 쓴 값이 
  꾸러미 위에서 어떤 식으로 보여지는지를 살펴보세요.


  주의 : 다른 프로세스로 부터 데이터를 받는 것에 보안이 되어있음을 잊지마세요.
         예로, Rect는 꾸러미로 부터 4개의 값을 읽지만 이것은 동의 하에 안전하게 올려졌습니다.
         하지만 이것은 위로 당신에게 안전하게 동의가능한 범위내의 무엇이든지 호출해서 시도하도록 만들어져 있습니다.
         구획화로부터 안전하게 보호하는 방법을 알기 위해 안드로이드에서 보안, 권한에 관한 문서를 자주 참고하세요.


● IPC 메쏘드를 호출하기

 여기엔 당신의 원격 인터페이스를 호출할 수 있도록 클래스를 호출하는 단계 입니다.

 1. 당신이 정의해둔 .aidl 파일을 인터페이스 속성 변수로 선언합니다.

 2. ServiceConnection 을 구현합니다.

 3. ApplicationContext.bindService() 를 호출합니다. 서비스연결 완성된 것의 인수를 넘깁니다.

 4. 당신의 완성된 ServiceConnection.onServiceConnected() 것으로 IBinder 인스턴스 값을 받을 수 있습니다.
    YourInterfaceName.Stub.asInterface((IBinder)Service) 를 호출해서 Yourinterface 속성으로 변환후 넘깁니다.

 5. 메소드를 당신이 정의한 인터페이스로 호출합니다. 당신은 언제나 예외 점검에 잡힐 수 있습니다. DeadObjectException,
    어느것은 연결이 끊어질 수도 있습니다 : 이것은 오직 원격메소드를 통해 예외처리 검사를 해야 합니다.

 6. 연결을 해제합니다. ApplicationContext.unbindService() 를 인터페이스의 인스턴스와 함께 호출합니다.

 
 약간의 IPC 서비스 호출에 대해 덧붙이자면.

  * 오브젝트는 맞은편의 프로세스의 갯수를 참조합니다.
  * 당신은 익명의 오브젝트에 메소드 arguments를 보낼 수 있습니다.


  여기에 AIDL 로 만들어진 서비스를 호출하는 약간의 코드 예제가 있습니다. ApiDemos project로부터 원격 Activity 샘플을 참조하세요