Android 앱에서 서버를 부르는 코드가 액티비티마다 흩어져 있었다. 그것을 공통 클래스로 모으는 일을 맡았다. 타깃은 Android 2.2였다.
문제는 무엇을 묶어야 하는지 몰랐다는 것이다. 화면마다 주소가 다르고 넘기는 값도 다르다. 그럼 같은 것은 무엇인가.
Table of contents
Open Table of contents
문제 — 한 파일에 옮기기만 했다
액티비티에 있던 DefaultHttpClient 호출을 HttpUtil 이라는 클래스로 그대로 옮겼다. 메서드 이름만 다르게 붙였다.
public String getUserInfo(String userId) {
// 요청 만들고 보내고 받는 코드 전부
}
public String getPointList(String userId, int page) {
// 위와 거의 똑같은 코드가 또
}
옮기고 나니 HttpUtil 한 파일에 메서드가 열넷이었다. 줄 수는 그대로였다. 새 화면이 생기면 메서드를 하나 더 복사해 붙였다. 모아 놓기만 하면 공통이 되는 것이 아니었다.
지워 봐서 남는 것이 공통이었다
복사를 한 번 더 하려다 멈췄다. 열넷에서 진짜 다른 것이 무엇인지 세어 봤다. 한 줄씩 지워 보며 지워도 되는 것과 지우면 다른 메서드까지 깨지는 것을 갈랐다.
| 화면마다 다른가 | |
|---|---|
| 서버 주소의 뒷부분 | 다르다 |
| 넘기는 값 | 다르다 |
HttpGet 이냐 HttpPost 냐 | 다르다 |
| 서버 주소의 앞부분 | 같다 |
HttpConnectionParams 타임아웃 | 같다 |
| 세션 쿠키 유지 | 같다 |
UrlEncodedFormEntity 로 값 싣기 | 같다 |
응답 스트림을 String 으로 바꾸기 | 같다 |
| 오류가 났을 때 처리 | 같다 |
아래 여섯은 열넷 전부가 쓰고 있었다. 위 셋은 부르는 쪽이 정하는 것이었다.
공통은 모아 놓은 것이 아니라 빼면 전부가 깨지는 것이었다. 구조는 여기서 나왔다. HttpUtil 은 어떻게 보낼지를 알고 부르는 쪽은 무엇을 보낼지만 넘긴다.
매번 챙기는 값은 공통으로
서버가 요청마다 앱 버전과 기기 정보를 요구했다. 처음에는 값마다 파라미터로 넘겼다. 화면이 늘수록 같은 값 셋을 모든 호출에 넣게 됐다. 빠뜨린 화면이 둘 나왔다.
이건 헤더에 넣을 것이었다. 부르는 쪽이 신경 쓰지 않아도 HttpUtil 이 매번 붙이면 된다.
post.setHeader("X-App-Version", appVersion);
post.setHeader("X-Device", deviceInfo);
setHeader 를 공통 클래스 안으로 내리니 빠뜨릴 자리가 없어졌다. 부르는 쪽이 매번 챙기는 값이 있으면 그건 공통으로 내릴 신호였다.
기다리는 일을 어디서 돌릴까
목록을 부르는 화면에서 앱이 잠깐 굳었다. 메인 스레드에서 통신을 하고 있어서였다. 예외가 나지는 않고 그냥 굳는다.
AsyncTask 로 감싸 별도 스레드에서 부르고 결과를 화면으로 돌려주게 바꿨다.
new AsyncTask<Void, Void, String>() {
protected String doInBackground(Void... params) {
return api.call(...); // 여기는 기다려도 된다
}
protected void onPostExecute(String result) {
// 여기서 화면을 고친다
}
}.execute();
이 AsyncTask 를 HttpUtil 안에 넣을지 밖에 둘지 정해야 했다. 안에 넣으면 부르는 쪽이 편하다. 대신 onPostExecute 에서 결과를 어느 화면에 줄지 알아야 한다.
밖에 두기로 했다. HttpUtil 은 부르면 답을 준다까지만 한다. AsyncTask 는 액티비티가 만든다.
이게 맞는지는 아직 모르겠다. 메인 스레드에서 부르면 굳는다는 규칙을 공통 클래스가 강제해야 하는지는 판단이 안 선다.
실패를 null 하나로 돌려줬다
오류를 어떻게 돌려줄지도 남았다. 실패하는 경우가 넷이었다.
인터넷이 안 됨
서버가 응답을 안 줌
서버가 실패라고 답함
응답 형식이 깨짐
처음에는 전부 null 을 돌려줬다. 그랬더니 부르는 쪽이 왜 실패했는지 몰랐다. 그래서 항상 같은 문구만 띄웠다.
결과를 감싸는 객체를 만들어 성공 여부와 메시지를 함께 담게 했다. null 하나로는 넷을 구분할 수 없다.
정리
- 한 파일에 옮기는 것과 공통으로 만드는 것은 다른 일이다
- 옮기기만 하면 화면이 늘 때 메서드도 같이 는다
- 하나씩 지워 봐서 빼면 전부가 깨지는 것이 공통이다
HttpConnectionParams타임아웃과UrlEncodedFormEntity와 응답 변환이 그것이었다- 화면마다 다른 것은 부르는 쪽이 정한다
- 매번 챙겨야 하는 헤더는 부르는 쪽에 두면 빠뜨린다
AsyncTask는HttpUtil밖에 두고 액티비티가 만들게 했다- 실패를
null하나로 돌려주면 부르는 쪽이 아무 말도 못 한다