안드로이드의 HTTP 통신 라이브러리 고찰

이번 포스팅에서는 안드로이드의 HTTP 통신에 대해 알아보도록 하겠습니다.

# 안드로이드에서의 통신

앱에서 가장 많이 수행하는 처리중 하나는 서버에 데이터를 요청하고 받아온 데이터를 단말-다시말해 클라이언트의 화면에 표시하는 것입니다. 이 때 클라이언트와 서버가 통신하는 방식은 크게 소켓연결과 HTTP연결 두 가지로 나눌 수 있습니다.

# 소켓 연결

소켓은 네트워크 상의 두 프로그램 사이에서 일어나는 양방향 통신중 한 쪽의 엔드 포인트를 의미합니다. 여기서 엔드포인트란 IP와 포트의 조합을 뜻합니다.

소켓 연결방식에서는 클라이언트와 서버가 특정 포트를 통해 연결을 계속 유지하고 있기 때문에 실시간으로 양방향 통신을 할 수 있는데요, 주로 동영상 스트리밍이나, 온라인 게임등에서 사용되는 연결방식입니다.

Native Socket.IO and Android 에 소켓통신을 사용해서 채팅앱을 만드는 법을 설명하고 있으니 궁금하신분은 참고하시면 좋을 것 같습니다.

# HTTP 연결

HTTP는 HyperText Transfer Protocol의 약자로, 80번 포트를 사용하여 웹 상에서 정보를 주고받을 수 있는 프로토콜을 말합니다. HTTP 통신에서는 클라이언트가 서버에 헤더(header)와 바디(body)로 이루어진 메시지를 요청(request)합니다. 그러면 서버는 이 요청을 처리하고 응답코드와 함께 응답(response)을 반환하게 됩니다.

  • Connectionless : HTTP 연결은 소켓을 사용해서 접속을 만들지만, 용건이 있을때만 연결했다가 용건이 끝나면 연결을 끊게 되어 있습니다. 이걸 Connectionless하다고 표현하는데, 이렇게 하면 서버에 여유가 생겨 더 많은 접속요구에 대응할 수 있게 됩니다.

  • Stateless : 통신이 일어날때마다 새로운 접속을 생성하고 삭제하는 Connectionless 특징때문에 HTTP 통신에서는 기본적으로 서버가 클라이언트를 식별할 수가 없는데 이것을 Stateless하다고 합니다. 그래서 서버가 클라이언트를 기억해야 할 경우 쿠키나 세션, 혹은 토큰이라는 기술을 사용하게 됩니다.

# HTTP Method

HTTP Method란 클라이언트가 서버에 메시지를 보낼 때 어떠한 목적을 가졌는지 밝히는 것으로, 다음과 같은 것들이 있습니다. 일반적으로 많이 사용되는 GET, POST, PUT, DELETE 이외에도 여러가지 명령어들이 있습니다.

Method 설명
GET 서버에 리소스를 요청합니다. 서버를 수정하지 않기 때문에 safe method로 분류.
HEAD GET과 같지만 서버가 본문(body)을 포함하지 않음.
POST 클라이언트에서 요청한 URL에 본문의 내용으로 새로운 리소스를 생성.
PUT 클라이언트가 요청한 내용으로 서버의 리소스를 수정.
DELETE 서버의 리소스를 삭제.
CONNECT 요청 리소스에 대해 양방향 연결을 수립, 예로 프록시를 통한 SSL 연결수립에 사용될 수 있음.
OPTIONS 서버가 어떤 HTTP 메소드를 지원하는지 물어봄.
TRACE 메시지의 변조여부 확인을 위해, 서버가 수신한 클라이언트의 메시지를 반환하도록 함.
PATCH PUT은 리소스 전체를 수정하나, PATCH는 해당 리소스의 일부만을 수정.

# RESTful API

구글, 페이스북, 트위터, 네이버, 카카오 등 많은 IT회사는 자기 회사의 서비스를 이용할 수 있도록 REST API를 제공합니다. REST API라는게 뭘까요?

REST(Representational State Transfer)는 HTTP 기반으로 필요한 자원에 접근하는 방식을 정해놓은 네트워크 아키텍처입니다. 일반적으로 다음과 같은 기준을 만족하면 RESTful 하다고하며 RESTful하게 작동하도록 만든 API를 RESTful API라고 합니다.

  • 클라이언트와 서버의 분리
  • 무상태(Stateless)
  • 캐시 처리가 가능해야 함
  • 시스템이 계층화(Layered) 되어있어야 함
  • 일관성 있는 인터페이스

Http Method와 RESTful API의 대응은 다음 와 같이 정리할 수 있습니다.

HTTP Method CRUD Entire Collection (e.g. /customers) Specific Item (e.g. /customers/{id})
POST Create 201 (Created), ‘Location’ header with link to /customers/{id} containing new ID. 404 (Not Found), 409 (Conflict) if resource already exists..
GET Read 200 (OK), list of customers. Use pagination, sorting and filtering to navigate big lists. 200 (OK), single customer. 404 (Not Found), if ID not found or invalid.
PUT Update/Replace 405 (Method Not Allowed), unless you want to update/replace every resource in the entire collection. 200 (OK) or 204 (No Content). 404 (Not Found), if ID not found or invalid.
PATCH Update/Modify 405 (Method Not Allowed), unless you want to modify the collection itself. 200 (OK) or 204 (No Content). 404 (Not Found), if ID not found or invalid.
DELETE Delete 405 (Method Not Allowed), unless you want to delete the whole collection—not often desirable. 200 (OK). 404 (Not Found), if ID not found or invalid.

# Android HTTP 통신 라이브러리

안드로이드에는 HTTP 통신을 구현하는 여러가지 라이브러리가 있는데요, 여기서는 주요하게 사용된 몇 가지 라이브러리를 시간순으로 다루어보도록 하겠습니다.

# HttpClient

Http 통신을 용이하게 수행하기 위해 Apache에서 제작한 라이브러리입니다. 안드로이드 초기에 주로 사용되었으며 실제로는 HttpClient를 래핑한 DefaultHttpClient나, 안드로이드에 맞게 개수한 AndroidHttpClient가 사용되었습니다.

HttpClient는 안드로이드와 독립적으로 개발되는 라이브러리인지라 변경점을 안드로이드 SDK에 일괄적으로 즉시 반영할 수 없었습니다. 결국 버전이 뒤쳐지면서 버그가 계속 발생하게 되었고, HttpClient는 Android 5.1에서 Deprecated 되며 6.0에서는 아예 삭제되었습니다. 이 시기 클라이언트의 버그는 네이버 D2 블로그의 Android의 HTTP 클라이언트 라이브러리에 잘 정리되어 있으니 참고하시기 바랍니다.

# HttpUrlConnection

HttpClient를 삭제하면서 구글에서 제시한 대안이 HttpUrlConnection인데요, 기존의 URLConnection에 HTTP를 다루는데 필요한 메서드를 추가한 클래스입니다.

URL.openConnection()으로 얻어진 URLConnection 객체를 HttpURLConnection으로 캐스팅하여 데이터 송수신을 행하고 disconnect로 접속을 종료하는 방식으로 사용합니다.

1
2
3
4
5
6
7
8
   URL url = new URL("http://www.android.com/");
   HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
   try {
     InputStream in = new BufferedInputStream(urlConnection.getInputStream());
     readStream(in);
   } finally {
     urlConnection.disconnect();
   }

# Volley

HttpUrlConnection을 사용할 때는 Application Not Responding(ANR)을 피하기 위해 백그라운드 스레드도 만들어야하고, 버퍼를 통한 입출력도 준비해야 하고, 캐시나 예외처리도 한땀한땀 다 처리해 주어야 하는 불편함이 있었습니다.

그래서 구글에서는 HTTP 연결을 만들때마다 이런 귀찮은 일을 안해도 되는 라이브러리인 Volley를 2013년 Google I/O에서 발표했습니다. Volley는 다음과 같은 특징이 있다고 하네요.

  • Automatic scheduling of network requests.
  • Multiple concurrent network connections.
  • Transparent disk and memory response caching with standard HTTP cache coherence.
  • Support for request prioritization.
  • Cancellation request API. You can cancel a single request, or you can set blocks or scopes of requests to cancel.
  • Ease of customization, for example, for retry and backoff.
  • Strong ordering that makes it easy to correctly populate your UI with data fetched asynchronously from the network.
  • Debugging and tracing tools.

사용법은 다음과 같습니다. HTTP 메소드와 url 정보를 가진 Request를 만들어서 RequestQueue에 넣어줍니다. 그러면 Volley가 알아서 스레드를 만들고 HttpUrlConnection으로 통신을 수행한 뒤 response를 반환해줍니다. 코드를 보시면 HttpUrlConnection을 직접 사용할 때보다 코드가 더 읽기 쉬워진 것을 알 수 있습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
val textView = findViewById<TextView>(R.id.text)

val queue = Volley.newRequestQueue(this)
val url = "https://www.google.com"

val stringRequest = StringRequest(Request.Method.GET, url,
        Response.Listener<String> { response ->
            // Display the first 500 characters of the response string.
            textView.text = "Response is: ${response.substring(0, 500)}"
        },
        Response.ErrorListener { textView.text = "That didn't work!" })

queue.add(stringRequest)

# OkHttp

그런 와중에 2013년 5월 6일엔 Square에서 OkHttp라는 HTTP 클라이언트 라이브러리를 발표합니다. 이 라이브러리는 Okio와 코틀린을 활용해 쓰여졌고 다음과 같은 특징이 있습니다. Connection pooling과 Redirection을 도입해 접속을 더 안정적이게 하면서도, 속도를 개선시킬 수 있는 여러가지 기술이 적용된 것으로 보입니다.

  • HTTP/2 support allows all requests to the same host to share a socket.
  • Connection pooling reduces request latency (if HTTP/2 isn’t available).
  • Transparent GZIP shrinks download sizes.
  • Response caching avoids the network completely for repeat requests.

사용법은 다음과 같습니다. 클라이언트 인스턴스를 생성하고 리퀘스트 객체를 만들어 클라이언트에 전해주면 response가 반환되는 구조를 가지고 있습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
OkHttpClient client = new OkHttpClient();

String run(String url) throws IOException {
  Request request = new Request.Builder()
      .url(url)
      .build();

  try (Response response = client.newCall(request).execute()) {
    return response.body().string();
  }
}

# Retrofit

Retrofit은 OkHttp를 개발한 Square에서 2013/05/14 에 발표한 라이브러리입니다. HttpURLConnection을 사용하기 편하도록 랩핑한게 Volley라면 Retrofit은 OkHttp를 랩핑한 것입니다.

사용법은 다음과 같습니다. 우선 REST API 콜을 인터페이스 형식으로 준비합니다. 그리고 Retrofit 객체를 만들어서 인터페이스의 인스턴스를 생성합니다. 마지막으로 인터페이스를 동기 혹은 비동기적으로 구동시켜 response를 반환받게 되어 있습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();
GitHubService service = retrofit.create(GitHubService.class);

Call<List<Repo>> repos = service.listRepos("octocat");

# Ktor

Jetbrains에서 개발한 Ktor는 코틀린을 이용해 비동기 서버와 클라이언트를 구축할수 있게 해주는 라이브러리입니다. 1.6.3 버전까지 발표되어 있으며 현재도 활발한 업데이트가 이루어지고 있습니다

안드로이드에서의 사용법은 다음과 같습니다. 코루틴 스코프 안에서 Http 클라이언트를 만들어서 request를 보내고 response를 확인한 뒤, 클라이언트의 리소스를 close로 반환하면 됩니다.

1
2
3
4
5
6
CoroutineScope(Dispatchers.IO).launch {
  val client = HttpClient()
  val response: HttpResponse = client.get("https://ktor.io/")
  val stringBody: String = response.receive()
  client.close()
}

# Volley or Retrofit?

안드로이드의 통신 라이브러리로는 주로 Volley 나 Retrofit을 이용하실 겁니다. 그렇다면 둘 중 어느것을 사용해야 할까요?

VolleyRetrofit은 지금도 꾸준히 갱신되고 있는 라이브러리인데요, 두 라이브러리의 기능차이는 다음과 같이 정리할 수 있을 것 같습니다.

Function Volley Retrofit
Automatic Parsing No Yes
Caching Yes No
Retrying Yes No
Post Requests & Multipart uploads Yes Partly
Image Loading Built-in No

속도에 있어서는 Volley가 빠르다는 사람도 있고 Retrofit이 빠르다는 사람도 있습니다만 결국 밀리세컨드 스케일의 차이라 속도만으로 어느 한쪽을 선택하는건 어려울 것 같네요. 코드 가독성은 대부분 Retrofit이 더 좋다는 평가인 것 같습니다. 사용법을 보시고 더 편한 쪽을 선택하시면 될 것 같습니다.

개인적으로는 API 콜을 인터페이스로 정의해서 사용하는 Retrofit이 전체 구조를 파악하기 더 좋은것 같아 이쪽을 선호합니다. 한가지 재밌는 것은 구글의 권장 앱 아키텍처에서는 HTTP 통신에 Volley가 아닌 Retrofit을 추천하고 있다는 점입니다.

출처 : https://developer.android.com/jetpack/guide#recommended-app-arch

이렇게 해서 HTTP 통신과 안드로이드의 통신 라이브러리에 대해 알아보았습니다.

Built with Hugo
Theme Stack designed by Jimmy