Android 프로 세 스 통신 의 Messenger 와 AIDL 사용 에 대한 자세 한 설명
언급 된 프로 세 스 간 통신(IPC:Inter-Process Communication)은 안 드 로 이 드 시스템 에서 하나의 프로 세 스 가 다른 프로 세 스 의 메모리 에 직접 접근 할 수 없 기 때문에 서로 다른 프로 세 스 간 에 통신 하 는 메커니즘 을 제공 해 야 합 니 다.안 드 로 이 드 는 공식 적 으로 AIDL(Android Interface Definition Language)을 출시 했 습 니 다.이것 은 Binder 메커니즘 을 바탕 으로 합 니 다.
위 에서 언급 한 구성 요소 와 Service 통신 방법 은 세 가지 가 있다.
2.사용 시기
어떤 메커니즘 을 사용 할 것 인 지 를 확정 하기 전에 먼저 응용 장면 을 이해한다.Android 시스템 에서 구성 요소 와 서비스 통신 이 같은 프로 세 스 라면 첫 번 째 방식 을 사용 합 니 다.크로스 프로 세 스 통신 이 라면 두 번 째 와 세 번 째 를 사용 합 니 다.메 신 저 는 다 중 스 레 드 병행 요청 을 처리 할 수 없습니다.
3.AIDL 사용
AIDL 은 다 중 스 레 드 접근 요청 을 처리 할 수 있 기 때문에 AIDL 을 실현 하려 면 먼저 스 레 드 안전 을 확보 해 야 합 니 다.
Android Studio 의 프로젝트 디 렉 터 리 에서 new->AIDL->AIDL FIle 을 거꾸로 누 르 면 에 이 드 파일 을 새로 만 들 수 있 습 니 다.컴 파 일 러 는 app(껍질 프로젝트)/src/main/디 렉 터 리 에 에 에 이 드 파일 을 자동 으로 새로 만 들 고 기본적으로 에 이 드 파일 이 있 는 디 렉 터 리 로 폴 더 를 새로 만 들 수 있 습 니 다.
디 렉 터 리 구 조 는 다음 과 같 습 니 다.
그림-1 aidl 파일 디 렉 터 리 구조
수 동 으로 만 들 수도 있 고,aidl 인터페이스 가 정의 하 는 패키지 이름 도 프로젝트 패키지 이름과 다 를 수 있 습 니 다.aidl 파일 문법 은 자바 문법 과 비슷 합 니 다.aidl 이 정의 하 는 인터페이스 이름 은 파일 이름과 일치 해 야 하 며,사용자 정의 데이터 형식 을 전달 하 는 것 을 지원 하기 때문에 parcelable 인 터 페 이 스 를 실현 해 야 합 니 다.
IRemoteService.aidl
package com.demo.aidl;
import com.demo.aidl.ParcelableData;
interface IRemoteService {
/**
* pid
*/
int getPid();
/**
*
*/
String getServiceName();
/**
*
*/
void handleData(in ParcelableData data);
}
ParcelableData.aidl
package com.demo.aidl;
/**
*
*/
parcelable ParcelableData;
IRemoteServiceCallBack.aidl
package com.demo.aidl;
oneway interface IRemoteServiceCallBack {
void valueChanged(int value);
}
aidl 파일 이 정의 하 는 인터페이스 지원 데이터 형식 은 다음 과 같 습 니 다.aidl 파일 을 새로 만 든 후,rebuild 프로젝트 나 gradle assemble Debug(또는 gradle assemble Release)명령 으로 프로젝트 를 컴 파일 하여 구체 적 인 자바 코드 를 생 성 합 니 다.케이스 프로젝트/build/generated/aidl/디 렉 터 리 의 debug 또는 release 폴 더 에서 build 의 유형 에 따라 정 합 니 다.그림:
그림-2 adil 생 성 코드 디 렉 터 리 그림
AIDL 인터페이스 가 처음 발 표 된 후에 그 어떠한 수정 도 뒤로 호환성 을 유지 하고 클 라 이언 트 가 서비스 에 대한 사용 을 중단 하지 않도록 해 야 합 니 다.'aidl 파일 을 다른 응용 프로그램 에 복사 해 야 다른 응용 프로그램 이 서비스 에 접근 할 수 있 기 때문에 원본 인터페이스 에 대한 지원 을 유지 해 야 합 니 다.
3.2 실현 인터페이스
Android SDK 는.aidl 파일 에 따라 같은 이름 의 자바 파일 을 생 성 합 니 다.생 성 된 인터페이스 에는 Stub 의 추상 적 인 하위 클래스 가 있 습 니 다.이 클래스 는(implements)aidl 이 정의 하 는 인 터 페 이 스 를 실현 하 는 동시에 Binder 를 계승 합 니 다.
구체 적 인 코드 는 다음 과 같다.
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
@Override
public int getPid() throws RemoteException {
return Process.myPid();
}
@Override
public String getServiceName() throws RemoteException {
return RemoteService.this.getClass().getSimpleName();
}
@Override
public void handleData(ParcelableData data) throws RemoteException {
Toast.makeText(RemoteService.this, "num is " + data.num, Toast.LENGTH_SHORT).show();
}
@Override
public void registerCallback(IRemoteServiceCallBack cb) throws RemoteException {
if(cb != null) {
mCallBacks.register(cb);
}
}
@Override
public void unregisterCallback(IRemoteServiceCallBack cb) throws RemoteException {
if(cb != null) {
mCallBacks.unregister(cb);
}
}
};
현재 mBinder 는 Stub 류 의 인 스 턴 스 이자 Binder 입 니 다.서비스 정의 RPC 서비스 로 onBind()방법의 반환 대상 인 스 턴 스 입 니 다.AIDL 인터페이스 구현 주의사항:
인 터 페 이 스 를 실현 한 후 클 라 이언 트 에 게 인 터 페 이 스 를 노출 시 켜 클 라 이언 트 가 사용 할 수 있 도록 해 야 합 니 다.Stub 의 실례 화 대상 을 Service 의 onBind()방법의 반환 대상 으로 합 니 다.
public class RemoteService extends Service {
/**
*
*/
private final RemoteCallbackList<IRemoteServiceCallBack> mCallBacks = new RemoteCallbackList<>();
/**
* aidl
*/
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
@Override
public int getPid() throws RemoteException {
return Process.myPid();
}
@Override
public String getServiceName() throws RemoteException {
return RemoteService.this.getClass().getSimpleName();
}
@Override
public void handleData(ParcelableData data) throws RemoteException {
Toast.makeText(RemoteService.this, "num is " + data.num, Toast.LENGTH_SHORT).show();
}
@Override
public void registerCallback(IRemoteServiceCallBack cb) throws RemoteException {
if(cb != null) {
mCallBacks.register(cb);
}
}
@Override
public void unregisterCallback(IRemoteServiceCallBack cb) throws RemoteException {
if(cb != null) {
mCallBacks.unregister(cb);
}
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onDestroy() {
//
mCallBacks.kill();
}
}
3.4 클 라 이언 트 호출서 비 스 는 제3자 응용 프로그램 에 제공 되 고 다른 응용 프로그램 은 인터페이스 클래스 가 있어 야 하 며 클 라 이언 트 에서 같은 aidl 파일 을 만들어 야 한다(직접 복사 할 수 있다).
핵심 연결 원 격 서비스 코드:
/**
*
*/
private IRemoteService mService;
private ServiceConnection mConnection = new ServiceConnection() {
/**
*
*
* @param className
* @param service
*/
public void onServiceConnected(ComponentName className, IBinder service) {
mService = IRemoteService.Stub.asInterface(service);
}
/**
*
*
* @param className
*/
public void onServiceDisconnected(ComponentName className) {
mService = null;
}
};
/**
*
*/
private void doBindService() {
isBound = true;
Intent intent = new Intent(BindRemoteServiceActivity.this, RemoteService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
/**
*
*/
private void doUnbindService() {
if(isBound && mService != null) {
isBound = false;
try {
mService.unregisterCallback(mCallback);
} catch (RemoteException e) {
e.printStackTrace();
}
unbindService(mConnection);
}
}
/**
*
*/
private void doSendMsg() {
if(!isBound || mService == null) {
return;
}
ParcelableData data = new ParcelableData(1);
try {
mService.handleData(data);
} catch (RemoteException e) {
e.printStackTrace();
}
}
/**
*
*/
private void doGetServiceInfo() {
if(!isBound || mService == null) {
return;
}
try {
String info = mService.getServiceName();
mInfoTv.setText("Service info :" + info);
} catch (RemoteException e) {
e.printStackTrace();
}
}
상세 코드 가 길 게 붙 어 있 습 니 다.공사 주 소 를 붙 여 주세요!! 4.Messenger 사용
Messenger 의 사용 은 AIDL 에 비해 훨씬 편리 합 니 다.Messenger 는 Android 시스템 에서 자체 적 으로 가지 고 있 는 클래스 이기 때문에 서버 와 클 라 이언 트 는 AIDL 파일 을 만 들 필요 가 없습니다.
Messenger 는 받 은 정 보 를 처리 하고 서버 에서 승객 과 Messenger 를 통 해 쌍방 통신 을 실현 하 는 Handler 를 가지 고 있 습 니 다.
4.1 서버
코드 인 스 턴 스:
public class MessengerService extends Service {
public static final int MSG_REGISTER_CLIENT = 0X001;
public static final int MSG_UNREGISTER_CLIENT = 0X010;
public static final int MSG_HANDLE = 0X100;
private ArrayList<Messenger> mClients = new ArrayList<>();
private final Messenger mMessenger = new Messenger(new IncomingHandler());
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
@Override
public void onDestroy() {
Toast.makeText(this, "Remote Service Destroy", Toast.LENGTH_SHORT).show();
}
private class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REGISTER_CLIENT:
mClients.add(msg.replyTo);
break;
case MSG_UNREGISTER_CLIENT:
mClients.remove(msg.replyTo);
break;
case MSG_HANDLE:
for (Messenger mClient : mClients) {
try {
mClient.send(Message.obtain(null, MSG_HANDLE, msg.arg1, 0));
} catch (RemoteException e) {
e.printStackTrace();
mClients.remove(mClient);
}
}
break;
default:
super.handleMessage(msg);
}
}
};
}
4.2 클 라 이언 트핵심 코드:
/**
* messenger
*/
private Messenger mServiceWrapper;
/**
*
*/
final Messenger mMessenger = new Messenger(new IncomingHandler());
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mServiceWrapper = new Messenger(service);
mInfoTv.setText("Connected Service");
try {
//
Message msg = Message.obtain(null, MessengerService.MSG_REGISTER_CLIENT);
msg.replyTo = mMessenger;
mServiceWrapper.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
mServiceWrapper = null;
mInfoTv.setText("Disconnected");
}
};
/**
*
*/
private void doBindService() {
if(!isBound) {
bindService(new Intent(this, MessengerService.class), mConnection, Context.BIND_AUTO_CREATE);
isBound = true;
mInfoTv.setText("Binding...");
}
}
/**
*
*/
private void doUnbindService() {
if(isBound) {
if(mServiceWrapper != null) {
try {
Message msg = Message.obtain(null, MessengerService.MSG_UNREGISTER_CLIENT);
msg.replyTo = mMessenger;
mServiceWrapper.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
unbindService(mConnection);
isBound = false;
mInfoTv.setText("Unbinding...");
}
}
/**
*
*/
private void doSendMsg() {
if(mServiceWrapper != null) {
try {
Message msg = Message.obtain(null,
MessengerService.MSG_HANDLE, this.hashCode(), 0);
mServiceWrapper.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
4.3 클 라 이언 트 가 메 시 지 를 보 냅 니 다.Messenger 를 사용 하여 서버 에 메 시 지 를 보 냅 니 다.Messenger.send(Message)방법 을 사용 합 니 다.이 방법 은 구체 적 으로 다음 과 같 습 니 다.
public void send(Message message) throws RemoteException {
mTarget.send(message);
}
방법 내부 에서 mTarget.send(Message)방법 을 호출 합 니 다.Messenger 에서 mTarget 은 구조 방법 에서 할당 되 고 두 개의 구조 함수 가 있 습 니 다.
public Messenger(Handler target) {
mTarget = target.getIMessenger();
}
public Messenger(IBinder target) {
mTarget = IMessenger.Stub.asInterface(target);
}
첫 번 째 구조 함 수 는 이해 하기 쉽 습 니 다.mTarget.send(Message)는 실제 적 으로 Message 를 구조 함수 가 들 어 오 는 Handler 의 메시지 대기 열 에 넣 었 습 니 다.Demo 프로젝트 에서 서비스 측 이 승객 측 에 메 시 지 를 보 내 는 것 이 바로 이런 방법 입 니 다.두 번 째 구조 함 수 는 낯 이 익 지 않 습 니까?이것 이 바로 AIDL 정 의 를 얻 는 인터페이스 가 아 닙 니까?!!한 바퀴 돌 고 위 에 있 는 AIDL 로 돌 아 왔 습 니 다.클 라 이언 트 가 서버 에 메 시 지 를 보 내 는 것 은 사실상 AIDL 을 통 해 이 루어 졌 습 니 다.안 드 로 이 드 시스템 이 우 리 를 도와 포장 을 해 주 었 을 뿐 입 니 다.
마지막 으로 데모 첨부:demo
5.총화
여기 서 Android 에서 자주 사용 하 는 프로 세 스 통신 이 모두 정리 되 었 습 니 다.끝 난 셈 입 니 다.꽃 을 뿌리 는 셈 입 니 다!!여러분 의 학습 에 도움 이 되 기 를 바 랍 니 다.여러분 들 도 저 희 를 많이 응원 해 주시 기 바 랍 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.