'interceptor'에 해당되는 글 1건

  1. 2022.02.18 Retrofit with RxJava 1
Android2022. 2. 18. 15:02

RxJava의 가장 훌룡한 사용예에 해당하는 네트웍통신 예제로서 Retrofit만한게 없을것 같아 정리해 보겠다.

GitHub의 https://api.github.com/users/{사용자계정}/repos를 샘플로 진행하겠다.

 

내 계정으로 부터 위 통신을 수행하면 다음과 같은 응답이 내려온다

 

[
  {
    "id": 34425769,
    "node_id": "MDEwOlJlcG9zaXRvcnkzNDQyNTc2OQ==",
    "name": "JSWheelView",
    "full_name": "samse/JSWheelView",
    "private": false,
    "owner": {
      "login": "samse",
      "id": 3222919,
      "node_id": "MDQ6VXNlcjMyMjI5MTk=",
      "avatar_url": "https://avatars.githubusercontent.com/u/3222919?v=4",
      "gravatar_id": "",
      "url": "https://api.github.com/users/samse",
      "html_url": "https://github.com/samse",
      "followers_url": "https://api.github.com/users/samse/followers",
      "following_url": "https://api.github.com/users/samse/following{/other_user}",
      "gists_url": "https://api.github.com/users/samse/gists{/gist_id}",
      "starred_url": "https://api.github.com/users/samse/starred{/owner}{/repo}",
      "subscriptions_url": "https://api.github.com/users/samse/subscriptions",
      "organizations_url": "https://api.github.com/users/samse/orgs",
      "repos_url": "https://api.github.com/users/samse/repos",
      "events_url": "https://api.github.com/users/samse/events{/privacy}",
      "received_events_url": "https://api.github.com/users/samse/received_events",
      "type": "User",
      "site_admin": false
    },
    "html_url": "https://github.com/samse/JSWheelView",
    "description": "Wheel Control View",
    "fork": true,
    "url": "https://api.github.com/repos/samse/JSWheelView",
    "forks_url": "https://api.github.com/repos/samse/JSWheelView/forks",
    "keys_url": "https://api.github.com/repos/samse/JSWheelView/keys{/key_id}",
    "collaborators_url": "https://api.github.com/repos/samse/JSWheelView/collaborators{/collaborator}",
    "teams_url": "https://api.github.com/repos/samse/JSWheelView/teams",
    "hooks_url": "https://api.github.com/repos/samse/JSWheelView/hooks",
    "issue_events_url": "https://api.github.com/repos/samse/JSWheelView/issues/events{/number}",
    "events_url": "https://api.github.com/repos/samse/JSWheelView/events",
    "assignees_url": "https://api.github.com/repos/samse/JSWheelView/assignees{/user}",
    "branches_url": "https://api.github.com/repos/samse/JSWheelView/branches{/branch}",
    "tags_url": "https://api.github.com/repos/samse/JSWheelView/tags",
    "blobs_url": "https://api.github.com/repos/samse/JSWheelView/git/blobs{/sha}",
    "git_tags_url": "https://api.github.com/repos/samse/JSWheelView/git/tags{/sha}",
    "git_refs_url": "https://api.github.com/repos/samse/JSWheelView/git/refs{/sha}",
    "trees_url": "https://api.github.com/repos/samse/JSWheelView/git/trees{/sha}",
    "statuses_url": "https://api.github.com/repos/samse/JSWheelView/statuses/{sha}",
    "languages_url": "https://api.github.com/repos/samse/JSWheelView/languages",
    "stargazers_url": "https://api.github.com/repos/samse/JSWheelView/stargazers",
    "contributors_url": "https://api.github.com/repos/samse/JSWheelView/contributors",
    "subscribers_url": "https://api.github.com/repos/samse/JSWheelView/subscribers",
    "subscription_url": "https://api.github.com/repos/samse/JSWheelView/subscription",
    "commits_url": "https://api.github.com/repos/samse/JSWheelView/commits{/sha}",
    "git_commits_url": "https://api.github.com/repos/samse/JSWheelView/git/commits{/sha}",
    "comments_url": "https://api.github.com/repos/samse/JSWheelView/comments{/number}",
    "issue_comment_url": "https://api.github.com/repos/samse/JSWheelView/issues/comments{/number}",
    "contents_url": "https://api.github.com/repos/samse/JSWheelView/contents/{+path}",
    "compare_url": "https://api.github.com/repos/samse/JSWheelView/compare/{base}...{head}",
    "merges_url": "https://api.github.com/repos/samse/JSWheelView/merges",
    "archive_url": "https://api.github.com/repos/samse/JSWheelView/{archive_format}{/ref}",
    "downloads_url": "https://api.github.com/repos/samse/JSWheelView/downloads",
    "issues_url": "https://api.github.com/repos/samse/JSWheelView/issues{/number}",
    "pulls_url": "https://api.github.com/repos/samse/JSWheelView/pulls{/number}",
    "milestones_url": "https://api.github.com/repos/samse/JSWheelView/milestones{/number}",
    "notifications_url": "https://api.github.com/repos/samse/JSWheelView/notifications{?since,all,participating}",
    "labels_url": "https://api.github.com/repos/samse/JSWheelView/labels{/name}",
    "releases_url": "https://api.github.com/repos/samse/JSWheelView/releases{/id}",
    "deployments_url": "https://api.github.com/repos/samse/JSWheelView/deployments",
    "created_at": "2015-04-23T01:15:40Z",
    "updated_at": "2015-04-23T01:15:41Z",
    "pushed_at": "2015-04-01T05:44:23Z",
    "git_url": "git://github.com/samse/JSWheelView.git",
    "ssh_url": "git@github.com:samse/JSWheelView.git",
    "clone_url": "https://github.com/samse/JSWheelView.git",
    "svn_url": "https://github.com/samse/JSWheelView",
    "homepage": null,
    "size": 244,
    "stargazers_count": 0,
    "watchers_count": 0,
    "language": "Objective-C",
    "has_issues": false,
    "has_projects": true,
    "has_downloads": true,
    "has_wiki": true,
    "has_pages": false,
    "forks_count": 0,
    "mirror_url": null,
    "archived": false,
    "disabled": false,
    "open_issues_count": 0,

위 응답을 기준으로 data class를 먼저 정의한다.

 

data class Owner(val userId: String, val avatar_url: String, val url: String, val htmlUrl: String, val repos_url: String)
data class Repo(val name: String, val full_name: String, val private: Boolean, val owner: Owner, val htmlUrl: String,
val description: String)

인터페이스를 정의한다.

여기서는 같은 일을 하는 일반 Call<T>와 Observable<T>를 반환하는 두가지를 비교하기 위해 정의하였다.

interface GitHubService {
    @GET("users/{user}/repos")
    fun listRepos(@Path("user") user: String): Call<List<Repo>>
    @GET("users/{user}/repos")
    fun listReposRx(@Path("user") user: String): Observable<List<Repo>>

}

 

Retrofit 객체를 빌드한다.

RxJava2CallAdapterFactory를 추가하여 Observable를 반환할 수 있도록 한다.

    var retrofit: Retrofit? = Retrofit.Builder()
        .baseUrl("https://api.github.com/")
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
//        .client(createClient())
        .build()

일반 Call<T> 호출의 예

 

val service: GitHubService? = retrofit?.create(GitHubService::class.java)
service?.apply {
    val call: Call<List<Repo>> = listRepos("samse")
    call.enqueue(object : Callback<List<Repo>> {
        override fun onResponse(call: Call<List<Repo>>, response: Response<List<Repo>>) {
            println("###################################")
            println("ret ${response.body()}")
            println("###################################")
        }

        override fun onFailure(call: Call<List<Repo>>, t: Throwable) {
            t.printStackTrace()
        }
    })
}

 

RxJava Observable<T> 호출의 예

val service: GitHubService? = retrofit?.create(GitHubService::class.java)
service?.apply {
    listReposRx("samse")
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe ({ repos ->
            println("###################################")
            println("Repo count=${repos.size}")
            for (v in repos) {
                println("  $v")
            }
            println("###################################")
        }, { error ->
            println(error)
        })
}

Retrofit이 네트웍통신에 대한 모든 방식을 지원하고 귀찮은 예외처리까지 해주는 데다가 RxJava도 가능하니 이를 통해서 좀더 깔끔하고 가독성 좋은 코드를 생산할 수 있겠다.

 

Retrofit은 Interceptor를 통신 중간에 추가해 넣어서 송/수신 구간에 끼어 들어서 헤더에 정보를 추가하거나 통신로깅을 수행하는 등의 작업을 가능하게 해준다.

 

아래는 송신패킷에 임의의 헤더값을 추가해주는 Interceptor의 예이다.

 

class HttpLoggingInterceptor: Interceptor {
    override fun intercept(chain: Interceptor.Chain): okhttp3.Response = with(chain) {
        val newRequest = request().newBuilder()
            .addHeader("X-New-UA", "My custom header")
            .build()
        proceed(newRequest)
    }
}

 

이렇게 정의한 Interceptor는 Retrofit를 build할때 추가해준다.

 

var retrofit: Retrofit? = Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .client(createClient())
    .build()

fun createClient(): OkHttpClient {
    return OkHttpClient.Builder()
        .addInterceptor(HttpLoggingInterceptor())
        .build()
}

 

rxretrofit.zip
0.26MB

Posted by 삼스