Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

• Տຊ ହ޹(͔Θ΋ͱ ΍͔ͨ͢) • ॴଐɿגࣜձࣾ tech vein 
 (େࡕࢢதԝ۠ຊொ) • ϞόΠϧΞϓϦΤϯδχΞ
 (AndroidଟΊɺiOS΋ŧŔŕŪũƄŝſ) • ࢖ͬͨ͜ͱ͋Δ
 HTTPΫϥΠΞϯτϥΠϒϥϦ
 - AndroidQuery,Volley,OkHttp,Retrofit 2 ࣗݾ঺հ

Slide 3

Slide 3 text

Retrofitͱ͸

Slide 4

Slide 4 text

• Squareࣾ੡ • HTTPΫϥΠΞϯτ • 2016೥ʹv2ϦϦʔε • 2019/11/30 ݱࡏ2.6.1 • JavaϥΠϒϥϦ • Android or JavaͰॻ͔ΕͨαʔόʔͰಈ͘ • GitHubελʔ34.3k Retrofitͱ͸

Slide 5

Slide 5 text

RetrofitͷΞΠσΞ interface ApiService { }

Slide 6

Slide 6 text

RetrofitͷΞΠσΞ interface ApiService { } class HttpGitHubService : ApiService { // … }

Slide 7

Slide 7 text

RetrofitͷΞΠσΞ interface ApiService { }

Slide 8

Slide 8 text

RetrofitͷΞΠσΞ(ྫ) interface GitHubServiceWithoutRetrofit { suspend fun listRepos(user: String): List }

Slide 9

Slide 9 text

class GitHubServiceImpl : GitHubServiceWithoutRetrofit { override suspend fun listRepos(user: String): List { return withContext(Dispatchers.IO) { val url = URL("https://api.github.com/users/$user/repos") val urlConnection = url.openConnection() as HttpURLConnection val result: List 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 { 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()) } }

Slide 10

Slide 10 text

class GitHubServiceImpl : GitHubServiceWithoutRetrofit { override suspend fun listRepos(user: String): List { return withContext(Dispatchers.IO) { val url = URL("https://api.github.com/users/$user/repos") val urlConnection = url.openConnection() as HttpURLConnection val result: List 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 { 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 Λࢦఆ

Slide 11

Slide 11 text

class GitHubServiceImpl : GitHubServiceWithoutRetrofit { override suspend fun listRepos(user: String): List { return withContext(Dispatchers.IO) { val url = URL("https://api.github.com/users/$user/repos") val urlConnection = url.openConnection() as HttpURLConnection val result: List 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 { 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 ͨ͠Γ

Slide 12

Slide 12 text

class GitHubServiceImpl : GitHubServiceWithoutRetrofit { override suspend fun listRepos(user: String): List { return withContext(Dispatchers.IO) { val url = URL("https://api.github.com/users/$user/repos") val urlConnection = url.openConnection() as HttpURLConnection val result: List 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 { 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 ΛѻͬͨΓ

Slide 13

Slide 13 text

class GitHubServiceImpl : GitHubServiceWithoutRetrofit { override suspend fun listRepos(user: String): List { return withContext(Dispatchers.IO) { val url = URL("https://api.github.com/users/$user/repos") val urlConnection = url.openConnection() as HttpURLConnection val result: List 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 { 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 ΛѻͬͨΓ

Slide 14

Slide 14 text

class GitHubServiceImpl : GitHubServiceWithoutRetrofit { override suspend fun listRepos(user: String): List { return withContext(Dispatchers.IO) { val url = URL("https://api.github.com/users/$user/repos") val urlConnection = url.openConnection() as HttpURLConnection val result: List 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 { 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 ΛѻͬͨΓ

Slide 15

Slide 15 text

https://square.github.io/retrofit/

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

গ͠ͷઃఆͱ͍͏ͷ͸ class GitHubServiceImpl : GitHubServiceWithoutRetrofit { override suspend fun listRepos(user: String): List { … } } val gitHubServiceWithRetrofit: GitHubServiceWithRetrofit = Retrofit.Builder() .baseUrl("https://api.github.com/") .addConverterFactory(MyConverterFactory()) .build() .create(GitHubServiceWithRetrofit::class.java)

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

https://speakerdeck.com/yasi/how-retrofit2-works-try-making-your-own- converter

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

Retrofitͷ࢓૊Έ

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

retrofit.create(GitHubService::class.java) public T create(final Class 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); } }); }

Slide 30

Slide 30 text

retrofit.create(GitHubService::class.java) public T create(final Class 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); } }); }

Slide 31

Slide 31 text

retrofit.create(GitHubService::class.java) public T create(final Class 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); } }); }

Slide 32

Slide 32 text

retrofit.create(GitHubService::class.java) public T create(final Class 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); } }); }

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

Proxy.newProxyInstanceͷྫ interface Service { fun doSomething(value: Int) } fun create(service: Class): 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 }

Slide 35

Slide 35 text

Proxy.newProxyInstanceͷྫ interface Service { fun doSomething(value: Int) } fun create(service: Class): 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)

Slide 36

Slide 36 text

Proxy.newProxyInstanceͷྫ interface Service { fun doSomething(value: Int) } fun create(service: Class): 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

Slide 37

Slide 37 text

Proxy.newProxyInstanceͷྫ interface Service { fun doSomething(value: Int) } fun create(service: Class): 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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

gitHubService.listRepos("kwmt") val gitHubService: GitHubService = Retrofit.Builder() ɹɹɹɹɹ// লུ .create(GitHubService::class.java) public T create(final Class 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); } }); }

Slide 41

Slide 41 text

gitHubService.listRepos("kwmt") val gitHubService: GitHubService = Retrofit.Builder() ɹɹɹɹɹ// লུ .create(GitHubService::class.java) public T create(final Class 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); } }); }

Slide 42

Slide 42 text

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; }

Slide 43

Slide 43 text

ServiceMethod#parseAnnotations • ఆٛͨ͠ΠϯλʔϑΣΠεΛϦϑϨΫγϣϯͰ෼ղ͠ ͯΞϊςʔγϣϯ΍໭Γ஋ͷܕΛௐ΂ɺHTTPϦΫΤε τͰ͖Δ͔νΣοΫ͍ͯ͠·͢ɻʢͨͱ͑͹ɺPOSTͳ ͷʹbody͕ͳ͍ͱ͔ͩͱΤϥʔʹͳΓ·͢ɻʣ • ઃఆͨ͠CallAdapter΍ConverterΛHTTPϦΫΤετͰ ࢖͑ΔΑ͏ʹ͠·͢ɻ

Slide 44

Slide 44 text

CallAdapterͷ࢓૊Έ

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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; }

Slide 50

Slide 50 text

ServiceMethod#parseAnnotations

Slide 51

Slide 51 text

ServiceMethod#parseAnnotations

Slide 52

Slide 52 text

ServiceMethod#parseAnnotations

Slide 53

Slide 53 text

ServiceMethod#parseAnnotations

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

public T create(final Class 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); } }); }

Slide 60

Slide 60 text

public T create(final Class 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); } }); }

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

CallAdapterͷ࢖͍ํ(࣮૷ͷ࢓ํ)

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

CallAdapter Call → T

Slide 69

Slide 69 text

CallAdapter Call → T = interface MyCall { fun execute(): Response }

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

CallAdapterͰΤϥʔϋϯυϦϯά class MyCallAdapter( private val responseType: Type ) : CallAdapter> { override fun responseType(): Type = responseType override fun adapt(call: Call): MyCall { return object : MyCall { override fun execute(): Response { val response = call.execute() val code = response.code() // 401ͳΒϩάΠϯࣦഊ if(code == 401) { throw AuthException() } return response } } } }

Slide 75

Slide 75 text

• Retrofit͸ɺΠϯλʔϑΣΠεʹΞϊςʔγϣϯΛ͚ͭͨΓɺ RetrofitBuilderͰઃఆ͢Δ͚ͩͰɺHTTPϦΫΤετͰ͖Δ • Retrofit͸Proxy#newProxyInstanceΛ࢖͍ͬͯͯɺιʔεࣗಈ ੜ੒͍ͯ͠ΔΘ͚Ͱ͸ͳ͍ • CallAdapter.Factory#get͸CallAdapterΛฦ͚ͩ͢ • CallAdapter͸adaptϝιουͰCall͔Βಠࣗͷܕʹม׵Ͱ ͖Δ • CallAdapterͰΤϥʔϋϯυϦϯάՄೳ ·ͱΊ

Slide 76

Slide 76 text

https://github.com/kwmt/RetrofitSample ֬ೝͨ͠ϦϙδτϦ

Slide 77

Slide 77 text

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