Retrofit2の仕組み 〜CallAdapterを理解する〜 / How Retrofit2 works ~ Understand CallAdapter ~

Retrofit2の仕組み 〜CallAdapterを理解する〜 / How Retrofit2 works ~ Understand CallAdapter ~

Android研究&発表会#3で発表した資料です!
https://arap.connpass.com/event/153097/

サンプル
https://github.com/kwmt/RetrofitSample

Ce6acc3536b0e0340b5f0569d3394c9c?s=128

Yasutaka Kawamoto

November 30, 2019
Tweet

Transcript

  1. Retrofit2ͷ࢓૊Έ Androidݚڀ&ൃදձ #3 2019/11/30 ʙCallAdapterΛཧղ͢Δʙ

  2. • Տຊ ହ޹(͔Θ΋ͱ ΍͔ͨ͢) • ॴଐɿגࣜձࣾ tech vein 
 (େࡕࢢதԝ۠ຊொ)

    • ϞόΠϧΞϓϦΤϯδχΞ
 (AndroidଟΊɺiOS΋ŧŔŕŪũƄŝſ) • ࢖ͬͨ͜ͱ͋Δ
 HTTPΫϥΠΞϯτϥΠϒϥϦ
 - AndroidQuery,Volley,OkHttp,Retrofit 2 ࣗݾ঺հ
  3. Retrofitͱ͸

  4. • Squareࣾ੡ • HTTPΫϥΠΞϯτ • 2016೥ʹv2ϦϦʔε • 2019/11/30 ݱࡏ2.6.1 •

    JavaϥΠϒϥϦ • Android or JavaͰॻ͔ΕͨαʔόʔͰಈ͘ • GitHubελʔ34.3k Retrofitͱ͸
  5. RetrofitͷΞΠσΞ interface ApiService { }

  6. RetrofitͷΞΠσΞ interface ApiService { } class HttpGitHubService : ApiService {

    // … }
  7. RetrofitͷΞΠσΞ interface ApiService { }

  8. RetrofitͷΞΠσΞ(ྫ) interface GitHubServiceWithoutRetrofit { suspend fun listRepos(user: String): List<Repo> }

  9. class GitHubServiceImpl : GitHubServiceWithoutRetrofit { override suspend fun listRepos(user: String):

    List<Repo> { return withContext(Dispatchers.IO) { val url = URL("https://api.github.com/users/$user/repos") val urlConnection = url.openConnection() as HttpURLConnection val result: List<Repo> try { val inputStream = BufferedInputStream(urlConnection.inputStream) result = readStream(inputStream) } finally { urlConnection.disconnect() } return@withContext result } } private fun readStream(inputStream: BufferedInputStream) = inputStream.bufferedReader().use { convert(it) } private fun convert(reader: BufferedReader): List<Repo> { val content = StringBuilder() reader.use { var line = it.readLine() while (line != null) { content.append(line) line = it.readLine() } } return Json { strictMode = false } .parse(Repo.serializer().list, content.toString()) } }
  10. class GitHubServiceImpl : GitHubServiceWithoutRetrofit { override suspend fun listRepos(user: String):

    List<Repo> { return withContext(Dispatchers.IO) { val url = URL("https://api.github.com/users/$user/repos") val urlConnection = url.openConnection() as HttpURLConnection val result: List<Repo> try { val inputStream = BufferedInputStream(urlConnection.inputStream) result = readStream(inputStream) } finally { urlConnection.disconnect() } return@withContext result } } private fun readStream(inputStream: BufferedInputStream) = inputStream.bufferedReader().use { convert(it) } private fun convert(reader: BufferedReader): List<Repo> { val content = StringBuilder() reader.use { var line = it.readLine() while (line != null) { content.append(line) line = it.readLine() } } return Json { strictMode = false } .parse(Repo.serializer().list, content.toString()) } } URL Λࢦఆ
  11. class GitHubServiceImpl : GitHubServiceWithoutRetrofit { override suspend fun listRepos(user: String):

    List<Repo> { return withContext(Dispatchers.IO) { val url = URL("https://api.github.com/users/$user/repos") val urlConnection = url.openConnection() as HttpURLConnection val result: List<Repo> try { val inputStream = BufferedInputStream(urlConnection.inputStream) result = readStream(inputStream) } finally { urlConnection.disconnect() } return@withContext result } } private fun readStream(inputStream: BufferedInputStream) = inputStream.bufferedReader().use { convert(it) } private fun convert(reader: BufferedReader): List<Repo> { val content = StringBuilder() reader.use { var line = it.readLine() while (line != null) { content.append(line) line = it.readLine() } } return Json { strictMode = false } .parse(Repo.serializer().list, content.toString()) } } URL Λࢦఆ openConnneciton ͨ͠Γ
  12. class GitHubServiceImpl : GitHubServiceWithoutRetrofit { override suspend fun listRepos(user: String):

    List<Repo> { return withContext(Dispatchers.IO) { val url = URL("https://api.github.com/users/$user/repos") val urlConnection = url.openConnection() as HttpURLConnection val result: List<Repo> try { val inputStream = BufferedInputStream(urlConnection.inputStream) result = readStream(inputStream) } finally { urlConnection.disconnect() } return@withContext result } } private fun readStream(inputStream: BufferedInputStream) = inputStream.bufferedReader().use { convert(it) } private fun convert(reader: BufferedReader): List<Repo> { val content = StringBuilder() reader.use { var line = it.readLine() while (line != null) { content.append(line) line = it.readLine() } } return Json { strictMode = false } .parse(Repo.serializer().list, content.toString()) } } URL Λࢦఆ openConnneciton ͨ͠Γ InputStream ΛѻͬͨΓ
  13. class GitHubServiceImpl : GitHubServiceWithoutRetrofit { override suspend fun listRepos(user: String):

    List<Repo> { return withContext(Dispatchers.IO) { val url = URL("https://api.github.com/users/$user/repos") val urlConnection = url.openConnection() as HttpURLConnection val result: List<Repo> try { val inputStream = BufferedInputStream(urlConnection.inputStream) result = readStream(inputStream) } finally { urlConnection.disconnect() } return@withContext result } } private fun readStream(inputStream: BufferedInputStream) = inputStream.bufferedReader().use { convert(it) } private fun convert(reader: BufferedReader): List<Repo> { val content = StringBuilder() reader.use { var line = it.readLine() while (line != null) { content.append(line) line = it.readLine() } } return Json { strictMode = false } .parse(Repo.serializer().list, content.toString()) } } URL Λࢦఆ openConnneciton ͨ͠Γ Ϩεϙϯε݁ՌΛࢦ ఆͨ͠ܕʹม׵͢ΔͨΊ ͷ࣮૷ͨ͠Γ InputStream ΛѻͬͨΓ
  14. class GitHubServiceImpl : GitHubServiceWithoutRetrofit { override suspend fun listRepos(user: String):

    List<Repo> { return withContext(Dispatchers.IO) { val url = URL("https://api.github.com/users/$user/repos") val urlConnection = url.openConnection() as HttpURLConnection val result: List<Repo> try { val inputStream = BufferedInputStream(urlConnection.inputStream) result = readStream(inputStream) } finally { urlConnection.disconnect() } return@withContext result } } private fun readStream(inputStream: BufferedInputStream) = inputStream.bufferedReader().use { convert(it) } private fun convert(reader: BufferedReader): List<Repo> { val content = StringBuilder() reader.use { var line = it.readLine() while (line != null) { content.append(line) line = it.readLine() } } return Json { strictMode = false } .parse(Repo.serializer().list, content.toString()) } } URL Λࢦఆ openConnneciton ͨ͠Γ Ϩεϙϯε݁ՌΛࢦ ఆͨ͠ܕʹม׵͢ΔͨΊ ͷ࣮૷ͨ͠Γ connectionΛ ੾அͨ͠Γ InputStream ΛѻͬͨΓ
  15. https://square.github.io/retrofit/

  16. গ͠ͷઃఆͱ͍͏ͷ͸ interface GitHubServiceWithoutRetrofit { suspend fun listRepos(user: String): List<Repo> }

  17. গ͠ͷઃఆͱ͍͏ͷ͸ interface GitHubServiceWithoutRetrofit { suspend fun listRepos(user: String): List<Repo> }

    interface GitHubServiceWithRetrofit { @GET("users/{user}/repos") fun listRepos(@Path("user") user: String): Call<List<Repo>> }
  18. গ͠ͷઃఆͱ͍͏ͷ͸ interface GitHubServiceWithoutRetrofit { suspend fun listRepos(user: String): List<Repo> }

    interface GitHubServiceWithRetrofit { @GET("users/{user}/repos") fun listRepos(@Path("user") user: String): Call<List<Repo>> }
  19. গ͠ͷઃఆͱ͍͏ͷ͸ interface GitHubServiceWithoutRetrofit { suspend fun listRepos(user: String): List<Repo> }

    interface GitHubServiceWithRetrofit { @GET("users/{user}/repos") fun listRepos(@Path("user") user: String): Call<List<Repo>> }
  20. গ͠ͷઃఆͱ͍͏ͷ͸ class GitHubServiceImpl : GitHubServiceWithoutRetrofit { override suspend fun listRepos(user:

    String): List<Repo> { … } }
  21. গ͠ͷઃఆͱ͍͏ͷ͸ class GitHubServiceImpl : GitHubServiceWithoutRetrofit { override suspend fun listRepos(user:

    String): List<Repo> { … } } val gitHubServiceWithRetrofit: GitHubServiceWithRetrofit = Retrofit.Builder() .baseUrl("https://api.github.com/") .addConverterFactory(MyConverterFactory()) .build() .create(GitHubServiceWithRetrofit::class.java)
  22. ඞཁͳͷ͸͜Ε͚ͩ interface GitHubServiceWithRetrofit { @GET("users/{user}/repos") fun listRepos(@Path("user") user: String): Call<List<Repo>>

    } val gitHubServiceWithRetrofit: GitHubServiceWithRetrofit = Retrofit.Builder() .baseUrl("https://api.github.com/") .addConverterFactory(MyConverterFactory()) .addCallAdapterFactory(MyCallAdapterFactory()) .build() .create(GitHubServiceWithRetrofit::class.java)
  23. ඞཁͳͷ͸͜Ε͚ͩ interface GitHubServiceWithRetrofit { @GET("users/{user}/repos") fun listRepos(@Path("user") user: String): Call<List<Repo>>

    } val gitHubServiceWithRetrofit: GitHubServiceWithRetrofit = Retrofit.Builder() .baseUrl("https://api.github.com/") .addConverterFactory(MyConverterFactory()) .addCallAdapterFactory(MyCallAdapterFactory()) .build() .create(GitHubServiceWithRetrofit::class.java)
  24. https://speakerdeck.com/yasi/how-retrofit2-works-try-making-your-own- converter

  25. ඞཁͳͷ͸͜Ε͚ͩ interface GitHubServiceWithRetrofit { @GET("users/{user}/repos") fun listRepos(@Path("user") user: String): Call<List<Repo>>

    } val gitHubServiceWithRetrofit: GitHubServiceWithRetrofit = Retrofit.Builder() .baseUrl("https://api.github.com/") .addConverterFactory(MyConverterFactory()) .addCallAdapterFactory(MyCallAdapterFactory()) .build() .create(GitHubServiceWithRetrofit::class.java)
  26. Retrofitͷ࢓૊Έ

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

    val gitHubService: GitHubService = Retrofit.Builder() .baseUrl("https://api.github.com/") .addConverterFactory(MyConverterFactory()) .addCallAdapterFactory(MyCallAdapterFactory()) .build() .create(GitHubService::class.java)
  28. interface GitHubService { @GET("users/{user}/repos") fun listRepos(@Path("user") user: String): Call<List<Repo>> }

    val gitHubService: GitHubService = Retrofit.Builder() .baseUrl("https://api.github.com/") .addConverterFactory(MyConverterFactory()) .addCallAdapterFactory(MyCallAdapterFactory()) .build() .create(GitHubService::class.java)
  29. retrofit.create(GitHubService::class.java) public <T> T create(final Class<T> service) { ɹ// লུ

    return (T) Proxy.newProxyInstance( service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { @Override public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { ɹɹɹɹɹ // লུ return loadServiceMethod(method) .invoke(args != null ? args : emptyArgs); } }); }
  30. retrofit.create(GitHubService::class.java) public <T> T create(final Class<T> service) { ɹ// লུ

    return (T) Proxy.newProxyInstance( service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { @Override public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { ɹɹɹɹɹ // লུ return loadServiceMethod(method) .invoke(args != null ? args : emptyArgs); } }); }
  31. retrofit.create(GitHubService::class.java) public <T> T create(final Class<T> service) { ɹ// লུ

    return (T) Proxy.newProxyInstance( service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { @Override public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { ɹɹɹɹɹ // লུ return loadServiceMethod(method) .invoke(args != null ? args : emptyArgs); } }); }
  32. retrofit.create(GitHubService::class.java) public <T> T create(final Class<T> service) { ɹ// লུ

    return (T) Proxy.newProxyInstance( service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { @Override public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { ɹɹɹɹɹ // লུ return loadServiceMethod(method) .invoke(args != null ? args : emptyArgs); } }); }
  33. Proxy.newProxyInstanceͷྫ interface Service { fun doSomething(value: Int) }

  34. Proxy.newProxyInstanceͷྫ interface Service { fun doSomething(value: Int) } fun <T>

    create(service: Class<T>): T { return Proxy.newProxyInstance( service.classLoader, Array(1) { service }, InvocationHandler { proxy, method, args -> Log.d(TAG, "start") Log.d(TAG, method.name + if (args.isNotEmpty()) args[0] else "") Log.d(TAG, "end") } ) as T }
  35. Proxy.newProxyInstanceͷྫ interface Service { fun doSomething(value: Int) } fun <T>

    create(service: Class<T>): T { return Proxy.newProxyInstance( service.classLoader, Array(1) { service }, InvocationHandler { proxy, method, args -> Log.d(TAG, "start") Log.d(TAG, method.name + if (args.isNotEmpty()) args[0] else "") Log.d(TAG, "end") } ) as T } val service = create(Service::class.java) service.doSomething(1000)
  36. Proxy.newProxyInstanceͷྫ interface Service { fun doSomething(value: Int) } fun <T>

    create(service: Class<T>): T { return Proxy.newProxyInstance( service.classLoader, Array(1) { service }, InvocationHandler { proxy, method, args -> Log.d(TAG, "start") Log.d(TAG, method.name + if (args.isNotEmpty()) args[0] else "") Log.d(TAG, "end") } ) as T } val service = create(Service::class.java) service.doSomething(1000) ϩάग़ྗ start doSomething1000 end
  37. Proxy.newProxyInstanceͷྫ interface Service { fun doSomething(value: Int) } fun <T>

    create(service: Class<T>): T { return Proxy.newProxyInstance( service.classLoader, Array(1) { service }, InvocationHandler { proxy, method, args -> Log.d(TAG, "start") Log.d(TAG, method.name + if (args.isNotEmpty()) args[0] else "") Log.d(TAG, "end") } ) as T } val service = create(Service::class.java) service.doSomething(1000) ϩάग़ྗ start doSomething1000 end
  38. val gitHubService: GitHubService = Retrofit.Builder() ɹɹɹɹɹ// লུ .create(GitHubService::class.java)

  39. gitHubService.listRepos("kwmt") val gitHubService: GitHubService = Retrofit.Builder() ɹɹɹɹɹ// লུ .create(GitHubService::class.java)

  40. gitHubService.listRepos("kwmt") val gitHubService: GitHubService = Retrofit.Builder() ɹɹɹɹɹ// লུ .create(GitHubService::class.java) public

    <T> T create(final Class<T> service) { ɹ// লུ return (T) Proxy.newProxyInstance( service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { @Override public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { ɹɹɹɹɹ // লུ return loadServiceMethod(method) .invoke(args != null ? args : emptyArgs); } }); }
  41. gitHubService.listRepos("kwmt") val gitHubService: GitHubService = Retrofit.Builder() ɹɹɹɹɹ// লུ .create(GitHubService::class.java) public

    <T> T create(final Class<T> service) { ɹ// লུ return (T) Proxy.newProxyInstance( service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { @Override public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { ɹɹɹɹɹ // লུ return loadServiceMethod(method) .invoke(args != null ? args : emptyArgs); } }); }
  42. Retrofit#loadServiceMethod ServiceMethod<?> loadServiceMethod(Method method) { ServiceMethod<?> result = serviceMethodCache.get(method); if

    (result != null) return result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { result = ServiceMethod.parseAnnotations(this, method); serviceMethodCache.put(method, result); } } return result; }
  43. ServiceMethod#parseAnnotations • ఆٛͨ͠ΠϯλʔϑΣΠεΛϦϑϨΫγϣϯͰ෼ղ͠ ͯΞϊςʔγϣϯ΍໭Γ஋ͷܕΛௐ΂ɺHTTPϦΫΤε τͰ͖Δ͔νΣοΫ͍ͯ͠·͢ɻʢͨͱ͑͹ɺPOSTͳ ͷʹbody͕ͳ͍ͱ͔ͩͱΤϥʔʹͳΓ·͢ɻʣ • ઃఆͨ͠CallAdapter΍ConverterΛHTTPϦΫΤετͰ ࢖͑ΔΑ͏ʹ͠·͢ɻ

  44. CallAdapterͷ࢓૊Έ

  45. CallAdapterͱ͸ • ϨεϙϯεͷRܕΛ࣋ͭ CallΛTܕʹదԠ(adapt)ͤ͞Δ ΠϯλʔϑΣΠε • Πϯελϯε͸CallAdapter.FactoryʹΑͬͯੜ੒͞Ε ΔɻaddCallAdapterFactoryΛ࢖ͬͯRetrofitΠϯελϯ εʹ௥Ճ͠·͢ɻ https://square.github.io/retrofit/2.x/retrofit/retrofit2/

    CallAdapter.html
  46. ϨεϙϯεͷRܕΛ࣋ͭ CallΛTܕʹదԠ(adapt)ͤ͞ ΔΠϯλʔϑΣΠε

  47. ϨεϙϯεͷRܕΛ࣋ͭ CallΛTܕʹదԠ(adapt)ͤ͞ ΔΠϯλʔϑΣΠε

  48. Πϯελϯε͸CallAdapter.FactoryʹΑͬͯੜ੒

  49. Factory#getɺCallAdapter#adapt
 ͕ͲͷΑ͏ʹݺ͹Ε͍ͯΔ͔ʁ ServiceMethod<?> loadServiceMethod(Method method) { ServiceMethod<?> result = serviceMethodCache.get(method);

    if (result != null) return result; synchronized (serviceMethodCache) { result = serviceMethodCache.get(method); if (result == null) { result = ServiceMethod.parseAnnotations(this, method); serviceMethodCache.put(method, result); } } return result; }
  50. ServiceMethod#parseAnnotations

  51. ServiceMethod#parseAnnotations

  52. ServiceMethod#parseAnnotations

  53. ServiceMethod#parseAnnotations

  54. ServiceMethod#parseAnnotations val gitHubService: GitHubService = Retrofit.Builder() .baseUrl("https://api.github.com/") .addConverterFactory(MyConverterFactory()) .addCallAdapterFactory(MyCallAdapterFactory()) .build()

    .create(GitHubService::class.java)
  55. ServiceMethod#parseAnnotations val gitHubService: GitHubService = Retrofit.Builder() .baseUrl("https://api.github.com/") .addConverterFactory(MyConverterFactory()) .addCallAdapterFactory(MyCallAdapterFactory()) .build()

    .create(GitHubService::class.java)
  56. ServiceMethod#parseAnnotations // CallAdapter.Factoryऔಘ callAdapterFactories.get(i) // CallAdapterΛऔಘ .get();

  57. ServiceMethod#parseAnnotations // CallAdapter.Factoryऔಘ callAdapterFactories.get(i) // CallAdapterΛऔಘ .get();

  58. ServiceMethod#parseAnnotations // CallAdapter.Factoryऔಘ callAdapterFactories.get(i) // CallAdapterΛऔಘ .get();

  59. public <T> T create(final Class<T> service) { ɹ// লུ return

    (T) Proxy.newProxyInstance( service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { @Override public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { ɹɹɹɹɹ // লུ return loadServiceMethod(method) .invoke(args != null ? args : emptyArgs); } }); }
  60. public <T> T create(final Class<T> service) { ɹ// লུ return

    (T) Proxy.newProxyInstance( service.getClassLoader(), new Class<?>[] { service }, new InvocationHandler() { @Override public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable { ɹɹɹɹɹ // লུ return loadServiceMethod(method) .invoke(args != null ? args : emptyArgs); } }); }
  61. ServiceMethod#invoke @Override invoke() { // লུ return adapt(call, args); }

    @Override adapt(): T { return callAdapter.adapt(call); }
  62. ServiceMethod#invoke @Override invoke() { // লུ return adapt(call, args); }

    @Override adapt(): T { return callAdapter.adapt(call); }
  63. ServiceMethod#invoke @Override invoke() { // লུ return adapt(call, args); }

    @Override adapt(): T { return callAdapter.adapt(call); }
  64. CallAdapterͷ࢖͍ํ(࣮૷ͷ࢓ํ)

  65. CallAdapter.Factory class MyCallAdapterFactory : CallAdapter.Factory() { override fun get( returnType:

    Type, annotations: Array<Annotation>, retrofit: Retrofit ): CallAdapter<*, *>? { val responseType = getParameterUpperBound(0, returnType as ParameterizedType) return MyCallAdapter<Any>(responseType) } }
  66. CallAdapter.Factory class MyCallAdapterFactory : CallAdapter.Factory() { override fun get( returnType:

    Type, annotations: Array<Annotation>, retrofit: Retrofit ): CallAdapter<*, *>? { val responseType = getParameterUpperBound(0, returnType as ParameterizedType) return MyCallAdapter<Any>(responseType) } }
  67. CallAdapter.Factory class MyCallAdapterFactory : CallAdapter.Factory() { override fun get( returnType:

    Type, annotations: Array<Annotation>, retrofit: Retrofit ): CallAdapter<*, *>? { val responseType = getParameterUpperBound(0, returnType as ParameterizedType) return MyCallAdapter<Any>(responseType) } }
  68. CallAdapter Call<R> → T

  69. CallAdapter Call<R> → T = interface MyCall<R> { fun execute():

    Response<R> }
  70. CallAdapter Call<R> → T = interface MyCall<R> { fun execute():

    Response<R> } class MyCallAdapter<R>( private val responseType: Type ) : CallAdapter<R, MyCall<R>> { override fun responseType(): Type = responseType override fun adapt(call: Call<R>): MyCall<R> { return object : MyCall<R> { override fun execute(): Response<R> { return call.execute() } } } }
  71. CallAdapter Call<R> → T = interface MyCall<R> { fun execute():

    Response<R> } class MyCallAdapter<R>( private val responseType: Type ) : CallAdapter<R, MyCall<R>> { override fun responseType(): Type = responseType override fun adapt(call: Call<R>): MyCall<R> { return object : MyCall<R> { override fun execute(): Response<R> { return call.execute() } } } }
  72. CallAdapter Call<R> → T = interface MyCall<R> { fun execute():

    Response<R> } class MyCallAdapter<R>( private val responseType: Type ) : CallAdapter<R, MyCall<R>> { override fun responseType(): Type = responseType override fun adapt(call: Call<R>): MyCall<R> { return object : MyCall<R> { override fun execute(): Response<R> { return call.execute() } } } }
  73. CallAdapter Call<R> → T = interface MyCall<R> { fun execute():

    Response<R> } class MyCallAdapter<R>( private val responseType: Type ) : CallAdapter<R, MyCall<R>> { override fun responseType(): Type = responseType override fun adapt(call: Call<R>): MyCall<R> { return object : MyCall<R> { override fun execute(): Response<R> { return call.execute() } } } }
  74. CallAdapterͰΤϥʔϋϯυϦϯά class MyCallAdapter<R>( private val responseType: Type ) : CallAdapter<R,

    MyCall<R>> { override fun responseType(): Type = responseType override fun adapt(call: Call<R>): MyCall<R> { return object : MyCall<R> { override fun execute(): Response<R> { val response = call.execute() val code = response.code() // 401ͳΒϩάΠϯࣦഊ if(code == 401) { throw AuthException() } return response } } } }
  75. • Retrofit͸ɺΠϯλʔϑΣΠεʹΞϊςʔγϣϯΛ͚ͭͨΓɺ RetrofitBuilderͰઃఆ͢Δ͚ͩͰɺHTTPϦΫΤετͰ͖Δ • Retrofit͸Proxy#newProxyInstanceΛ࢖͍ͬͯͯɺιʔεࣗಈ ੜ੒͍ͯ͠ΔΘ͚Ͱ͸ͳ͍ • CallAdapter.Factory#get͸CallAdapterΛฦ͚ͩ͢ • CallAdapter͸adaptϝιουͰCall<R>͔Βಠࣗͷܕʹม׵Ͱ

    ͖Δ • CallAdapterͰΤϥʔϋϯυϦϯάՄೳ ·ͱΊ
  76. https://github.com/kwmt/RetrofitSample ֬ೝͨ͠ϦϙδτϦ

  77. ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ @kwmt27