개발/Android Studio

[android] aidl, multiprocess 통신

yeonlee 2023. 10. 12. 18:18

activity 와 service

안드로이드 4대 구성요소중 둘. activity 는 UI 즉 메인쓰레드 상의 모든 action 을 의미하고

service 는 백그라운드에서 주로 돌아간다.

activity 는 oncreate - onstart - onresume - onpause - onstop - ondestroy 순서로 진행되며 끝 2개씩을 쌍으로 생각할 수 있다. 또, 자식 activity 를 실행하기 위해선 StartActivityForResult 를 쓰고, 자식 activitiy 에서 무언가를 받아야 한다며 OnActivityResult 를 사용한다.

생명주기에 대한 자세한 내용, activity 의 선언, activity 의 이동에 대해선 다음 포스팅을 참고하면 좋다

https://yeon-lee.tistory.com/126

service 는 oncreate, ondestroy 를 공유하고, startservice, bindservice 두가지 실행 시나리오가 있으며 startservice 는 onstartcommand 로 실행이 되고 독립적으로 실행되는 반면 bindservice 는 onbind 로 구성요소에 bind 되어 생명주기를 함께한다.

더 자세한 서비스에 대한 내용은 다음 포스팅을 참고하면 좋다

https://yeon-lee.tistory.com/128

aidl

https://kjwsx23.tistory.com/187

activity 에서 socket 통신을 해야한다. service 에서 bind, listen, connect 등을 진행하고 해당 결과를 activity 로 받아야 해서 위 링크를 참고해서 만들었다.

aidl 양방향 : https://yeon-lee.tistory.com/193 aidl 통신 : https://yeon-lee.tistory.com/194 https://yeon-lee.tistory.com/189 aidl 구조 : https://yeon-lee.tistory.com/137 https://yeon-lee.tistory.com/127 https://yeon-lee.tistory.com/125

socketmanager 라는 객체를 application 을 상속받아서 singleton 으로 구현하였다. activity 가 통신할 때 동일한 소켓만을 사용하게 하고, 어떤 activity 에서도 접근해서 사용할 수 있게 하기 위함이다. 또, 앱의 모든 생명주기 상에 존재하기에 background 작업을 하는 service 와 함께 사용하기에 적절했다.

public class SocketManager extends Application {
    private static final SocketManager instance = new SocketManager();
		...

실제 socket connect 를 담당할 connectionService 에는 interface.stub 대로 구현한 binder 객체를 정의를 다음과 같이 합니다.

IConnectionService.Stub binder = new IConnectionService.Stub() {
        @Override
        public int getStatus() throws RemoteException {
            return status;
        }

        @Override
        public void setSocket(String ip) throws RemoteException {
            mySetSocket(ip);
        }

        @Override
        public void connect() throws RemoteException {
            myConnect();
        }

        @Override
        public void disconnect() throws RemoteException {
            myDisconnect();
        }

        @Override
        public void send() throws RemoteException {
            mySend();
        }

        @Override
        public void receive() throws RemoteException {
            myReceive();
        }
    };

service에서 정의한 이 binder 를 socketManager 에서 사용함으로써 activity 에서 소켓 통신을 할 수 있도록 구현하였습니다.

cgMsg = manager.getCG(sendCGMsg.msgId, i++);

보면 get 하는 부분을 loop 를 사용해서 msgID, msgSubID 형식으로 받고 있는데 이는 대용량 파일을 효과적으로 처리하기 위해서 이중 해쉬맵을 이용했다. 큰 파일을 <msgID, <msgSubId, JSON>> 형식으로 담았고 이를 순차적으로 꺼내는 구조를 가진다.

static HashMap<Integer, HashMap<Integer, JSONObject>> cgMsgMap = new HashMap<>();
	void pushCGMsgToMap(JSONObject obj) {
		try {
			int msgId = obj.getInt("msg_id");
			synchronized (cgMsgMap) {
				HashMap<Integer, JSONObject> subMsgMap;
				subMsgMap = cgMsgMap.get(msgId);
				if (subMsgMap != null) {
					subMsgMap.put(obj.getInt("msg_sub_id"), obj);
				} else {
					subMsgMap = new HashMap<>();
					subMsgMap.put(obj.getInt("msg_sub_id"), obj);
					cgMsgMap.put(msgId, subMsgMap);
				}
				cgMsgMap.notify();
			}
		} catch (JSONException e) { }
	}