你好,我正在使用retrofit和rxjava2异步工作
和我必须从头部得到的值,而与服务器开发人员交谈。
然而,我不知道如何从我使用的方法获得标题。我知道如何从Call Response中获取它,但我不知道如何带来header,因为使用的方法不同。
my retrofit2 class
private val retrofit: Retrofit = Retrofit.Builder()
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(client())
.baseUrl(serverIp)
.build()
val userApi: UserAPI = retrofit.create(UserAPI::class.java)
my model class
@POST("user")
fun login(
@Body loginRequest : LoginRequest
) : Single<UserResponse>
data class LoginRequest(
val phone: String?,
@SerializedName("gender")
val gender: String?,
@SerializedName("age")
val age: String?,
@SerializedName("email")
val email: String?
)
data class UserResponse (
override var status: Int,
override var message: String,
override var timestamp: String,
var data: Data
) : CommonResponse() {
data class Data(
var username: String?,
var token: String?
)
}
my viewModel (rx)
addDisposable(
model.loginBody(loginRequest)
.subscribeOn(Schedulers.io())
.subscribe({
_loginResult.postValue(it)
}, {
Timber.d("response error, message : ${it.localizedMessage}")
})
)
我目前的情况如下。我需要登录后服务器返回的头,我可以从okhttp日志中看到它,但我不知道如何获得特定的头
要检索响应头和其他有用的信息,您可以使用retrofit2包中的Response
类型。要使用此方法,请将登录方法的返回类型更改为Single<retrofit2.Response<UserResponse>>
@POST("user")
fun login( @Body loginRequest : LoginRequest): Single<retrofit2.Response<UserResponse>>
现在在ViewModel
中检索标题addDisposable(
model.loginBody(loginRequest)
.subscribeOn(Schedulers.io())
.subscribe({
val headers = it.headers() // do something with headers
val data = it.body()
_loginResult.postValue(data)
}, {
Timber.d("response error, message : ${it.localizedMessage}")
})
)
建议而非解决方案
不是解决问题的问题,而是即使很晚了,因为你使用Kotlin,更好的解决方案是从rxJava迁移到Kotlin Flow。它允许你使用suspend
函数来做你的改造调用,然后使用Kotlin Flow在IO线程上做rxJava的工作。
它还允许您以更简单的方式使用Response<T>
改装对象。
例子:
改造请求
@POST(YOUR_ROAD) // Retrofit road
suspend fun connect(
@Body credentials: CredentialsObjectBody
): Response<ConnectionObjectResponse>
对改造请求的存储库调用
// The function is suspending the thread with suspend keyword
suspend fun yourFunction(): Flow<DataState<TypeForEmitter>> = flow {
try {
body.clientId = sessionPrefs.deviceName!!
val connectionResponse =
majorApi.connect(
// what you need to put in the body
)
.apply {
if (isSuccessful) {
body()?.let {
// Here you can use what's in the request body
emit(DataState.Success(it))
} ?: throw Exception("Request body was null")
} else {
throw Exception(headers()["message"]) // use throw to handle the error in the catch
}
}
} catch (e: Exception) {
Log.e(TAG, "error: ${e.message}")
emit(DataState.Error(e))
}
}
DataState:
DataState是一个密封类,允许区分发出的状态sealed class DataState<out R> {
data class Success<out T>(val data: T) : DataState<T>()
data class Error(val exception: Exception) : DataState<Nothing>()
object Loading : DataState<Nothing>()
}
如何调用Kotlin流以在IO线程上启动它以防止阻塞Main(或UI)线程
withContext(Dispatchers.IO) {
yourFunction().onEach {
/*
onEach is like onNext, but emits every type of error, compared to rxJava
that differentiates next/success, complete and error events
*/
}
}