-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
创建方式改变为FlowCallAdapterFactory.create()和FlowCallAdapterFactory.createA…
…sync(),现在支持同步请求。
- Loading branch information
Showing
9 changed files
with
141 additions
and
87 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
79 changes: 79 additions & 0 deletions
79
adapter-flow/src/main/java/com/chenxyu/retrofit/adapter/CallFlow.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package com.chenxyu.retrofit.adapter | ||
|
||
import kotlinx.coroutines.CancellationException | ||
import kotlinx.coroutines.ExperimentalCoroutinesApi | ||
import kotlinx.coroutines.cancel | ||
import kotlinx.coroutines.channels.* | ||
import retrofit2.Call | ||
import retrofit2.Callback | ||
import retrofit2.Response | ||
|
||
/** | ||
* @Author: ChenXingYu | ||
* @CreateDate: 2021/7/21 1:46 | ||
* @Description: | ||
* @Version: 1.0 | ||
*/ | ||
@ExperimentalCoroutinesApi | ||
internal fun <R> ProducerScope<R>.callEnqueueFlow(call: Call<R>) { | ||
call.enqueue(object : Callback<R> { | ||
override fun onResponse(call: Call<R>, response: Response<R>) { | ||
processing(response) | ||
} | ||
|
||
override fun onFailure(call: Call<R>, throwable: Throwable) { | ||
cancel(CancellationException(throwable.localizedMessage, throwable)) | ||
} | ||
}) | ||
} | ||
|
||
@ExperimentalCoroutinesApi | ||
internal fun <R> ProducerScope<R>.callExecuteFlow(call: Call<R>) { | ||
try { | ||
processing(call.execute()) | ||
} catch (throwable: Throwable) { | ||
cancel(CancellationException(throwable.localizedMessage, throwable)) | ||
} | ||
} | ||
|
||
@ExperimentalCoroutinesApi | ||
internal fun <R> ProducerScope<R>.processing(response: Response<R>) { | ||
if (response.isSuccessful) { | ||
val body = response.body() | ||
if (body == null || response.code() == 204) { | ||
cancel(CancellationException("HTTP status code: ${response.code()}")) | ||
} else { | ||
trySendBlocking(body) | ||
.onSuccess { | ||
close() | ||
} | ||
.onClosed { throwable -> | ||
cancel( | ||
CancellationException( | ||
throwable?.localizedMessage, | ||
throwable | ||
) | ||
) | ||
} | ||
.onFailure { throwable -> | ||
cancel( | ||
CancellationException( | ||
throwable?.localizedMessage, | ||
throwable | ||
) | ||
) | ||
} | ||
} | ||
} else { | ||
val msg = response.errorBody()?.string() | ||
cancel( | ||
CancellationException( | ||
if (msg.isNullOrEmpty()) { | ||
response.message() | ||
} else { | ||
msg | ||
} ?: "unknown error" | ||
) | ||
) | ||
} | ||
} |
54 changes: 12 additions & 42 deletions
54
adapter-flow/src/main/java/com/chenxyu/retrofit/adapter/FlowCallAdapter.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,68 +1,38 @@ | ||
package com.chenxyu.retrofit.adapter | ||
|
||
import kotlinx.coroutines.CancellationException | ||
import kotlinx.coroutines.ExperimentalCoroutinesApi | ||
import kotlinx.coroutines.cancel | ||
import kotlinx.coroutines.channels.awaitClose | ||
import kotlinx.coroutines.channels.sendBlocking | ||
import kotlinx.coroutines.flow.Flow | ||
import kotlinx.coroutines.flow.callbackFlow | ||
import retrofit2.Call | ||
import retrofit2.CallAdapter | ||
import retrofit2.Callback | ||
import retrofit2.Response | ||
import java.lang.reflect.Type | ||
import java.util.concurrent.atomic.AtomicBoolean | ||
|
||
/** | ||
* @Author ChenXingYu | ||
* @Date 2020/4/9-15:21 | ||
*/ | ||
internal class FlowCallAdapter<R>(private val responseType: Type) : | ||
CallAdapter<R, Flow<R?>> { | ||
internal class FlowCallAdapter<R>( | ||
private val responseType: Type, | ||
private val isAsync: Boolean | ||
) : CallAdapter<R, Flow<R?>> { | ||
|
||
override fun responseType() = responseType | ||
|
||
@ExperimentalCoroutinesApi | ||
override fun adapt(call: Call<R>): Flow<R?> { | ||
return callFlow(call, isAsync) | ||
} | ||
|
||
@ExperimentalCoroutinesApi | ||
private fun <R> callFlow(call: Call<R>, isAsync: Boolean): Flow<R> { | ||
val started = AtomicBoolean(false) | ||
return callbackFlow { | ||
val started = AtomicBoolean(false) | ||
if (started.compareAndSet(false, true)) { | ||
call.enqueue(object : Callback<R> { | ||
override fun onResponse(call: Call<R>, response: Response<R>) { | ||
if (response.isSuccessful) { | ||
val body = response.body() | ||
if (body == null || response.code() == 204) { | ||
cancel(CancellationException("HTTP status code: ${response.code()}")) | ||
} else { | ||
try { | ||
sendBlocking(body) | ||
close() | ||
} catch (e: Exception) { | ||
cancel(CancellationException(e.localizedMessage, e)) | ||
} | ||
} | ||
} else { | ||
cancel(CancellationException(errorMsg(response) ?: "unknown error")) | ||
} | ||
} | ||
|
||
override fun onFailure(call: Call<R>, throwable: Throwable) { | ||
cancel(CancellationException(throwable.localizedMessage, throwable)) | ||
} | ||
}) | ||
if (isAsync) callEnqueueFlow(call) else callExecuteFlow(call) | ||
awaitClose { call.cancel() } | ||
} | ||
awaitClose { call.cancel() } | ||
} | ||
} | ||
|
||
private fun errorMsg(response: Response<R>): String? { | ||
val msg = response.errorBody()?.string() | ||
return if (msg.isNullOrEmpty()) { | ||
response.message() | ||
} else { | ||
msg | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters