Android Service ex. (w/ AIDL)
2025. 6. 11. 10:32ㆍFrontend/Android
- 목차
반응형
defininition
두 숫자를 입력으로 받아 합한 결과를 제공하는 간단한 서비스를 정의해 보겠습니다.
다음과 같이 add 메서드를 선언한 IMyAidlInterface라는 이름의 인터페이스를 정의합니다.
defines AIDL file
// IMyAidlInterface.aidl
package com.example.aidl;
interface IMyAidlInterface {
int add(int x, int y);
}
Generated code
Build > Make Project를 수행하면 다음의 파일이 생성됩니다.
app/build/generated/aidl_source_output_dir/debug/out/com/example/aidl/IMyAidlInterface.java
생성된 파일의 내용은 다음과 같습니다.
package com.example.aidl;
public interface IMyAidlInterface extends android.os.IInterface {
public int add(int x, int y) throws android.os.RemoteException;
public static abstract class Stub extends android.os.Binder implements IMyAidlInterface {
public Stub() { /* ... */ }
// asInterface: IBinder → IMyAidlInterface로 변환
public static IMyAidlInterface asInterface(android.os.IBinder obj) { /* ... */ }
@Override
public android.os.IBinder asBinder() {
return this;
}
// onTransact: Binder IPC 메시지를 실제 메서드로 변환
@Override
protected 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_add:
data.enforceInterface(DESCRIPTOR);
int x = data.readInt();
int y = data.readInt();
int result = this.add(x, y);
reply.writeNoException();
reply.writeInt(result);
return true;
}
return super.onTransact(code, data, reply, flags);
}
}
public static class Default implements IMyAidlInterface {
@Override
public int add(int x, int y) throws android.os.RemoteException {
return 0;
}
}
// Proxy: 클라이언트에서 실제로 Binder에 호출을 넘기는 역할
public static class Proxy implements IMyAidlInterface {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public int add(int x, int y) throws android.os.RemoteException {
android.os.Parcel data = android.os.Parcel.obtain();
android.os.Parcel reply = android.os.Parcel.obtain();
int result;
try {
data.writeInterfaceToken(DESCRIPTOR);
data.writeInt(x);
data.writeInt(y);
mRemote.transact(Stub.TRANSACTION_add, data, reply, 0);
reply.readException();
result = reply.readInt();
} finally {
data.recycle();
reply.recycle();
}
return result;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
}
}
Usage
이를 상속 받아 서비스를 제공하는 코드를 작성합니다.
service side
class MyService : Service() {
// Stub을 상속해서 메서드 구현
private val binder = object : IMyAidlInterface.Stub() {
override fun add(x: Int, y: Int): Int {
return x + y
}
}
override fun onBind(intent: Intent): IBinder {
return binder
}
}
AndroidManifest.xml에는 서비스를 등록합니다.
<service
android:name=".MyService"
android:exported="true">
<intent-filter>
<action android:name="com.example.aidl.IMyAidlInterface" />
</intent-filter>
</service>
client side
ServiceConnection을 상속받는 객체를 생성하고 onServiceConnected callback이 불릴때 proxy 객체를 얻습니다.
이후 onCreate 시 myAidl?.add를 호출해서 서비스가 제공하는 기능을 RPC로서 수행을 요청합니다.
class MainActivity : AppCompatActivity() {
private var myAidl: IMyAidlInterface? = null
private var isBound = false
private val connection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
myAidl = IMyAidlInterface.Stub.asInterface(service)
isBound = true
}
override fun onServiceDisconnected(name: ComponentName?) {
myAidl = null
isBound = false
}
}
override fun onStart() {
super.onStart()
val intent = Intent("com.example.aidl.IMyAidlInterface")
intent.setPackage("com.example.aidl") // 서비스 패키지명
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
override fun onStop() {
super.onStop()
if (isBound) {
unbindService(connection)
isBound = false
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 예시: 버튼 클릭 시 AIDL 메서드 호출
findViewById<Button>(R.id.btn_add).setOnClickListener {
if (isBound && myAidl != null) {
val x = 10
val y = 20
try {
val result = myAidl?.add(x, y)
Toast.makeText(this, "Result: $result", Toast.LENGTH_SHORT).show()
} catch (e: RemoteException) {
e.printStackTrace()
}
} else {
Toast.makeText(this, "서비스 연결 안 됨", Toast.LENGTH_SHORT).show()
}
}
}
}
반응형
'Frontend > Android' 카테고리의 다른 글
Flow usage pattern (0) | 2025.06.19 |
---|---|
Android Studio 심볼(함수, 변수 등) 정의 부분으로 가기가 안되는 경우 (0) | 2025.05.07 |
오래된 장치(폰)에서 안드로이드 앱을 실행하는 방법 (0) | 2025.03.18 |
LiveData 사용 이유 (0) | 2025.02.27 |
Android에서 Unresolved reference: activity_main 에러 (0) | 2023.02.16 |