提问人:Dean Ball 提问时间:11/6/2023 更新时间:11/6/2023 访问量:48
改造响应为 null,但 okHttp Interceptor 记录器有数据
Retrofit response is null but okHttp Interceptor logger has data
问:
我有一个 POST 请求,要根据生成的 SessionKey 获取数据。如果 SessionKey 有效,则会响应某些 Customer 数据。
我面临的问题是我的 Retrofit 实例给了我空响应,但 okHttp Interceptor 记录器正在返回数据,如 Logcat 中所示。
我显然在某个地方出了问题,谁能给我指出正确的方向?希望这很简单!
API结构
<OrderInfoResponse
<OrderInfoResult>
<deliveryAddresses>
<OrderingDeliveryAddressStruct>
<deliveryAddressNo>string</deliveryAddressNo>
<deliveryAddressName>string</deliveryAddressName>
<pointsOfService>
<OrderingPointOfServiceStruct>
<pointOfServiceNo>string</pointOfServiceNo>
<pointOfServiceName>string</pointOfServiceName>
<pointOfServiceDescription>string</pointOfServiceDescription>
<pointOfServiceOrderingGroupNo>string</pointOfServiceOrderingGroupNo>
<orders>
<OrderingOrderStruct>
<orderType>string</orderType>
<orderDate>date</orderDate>
<deliveryDate>date</deliveryDate>
<orderStatus>int</orderStatus>
<articles>
<OrderingArticleStruct>
<articleNo>string</articleNo>
<articleDescription>string</articleDescription>
<articleSize>string</articleSize>
<articleTargetQty>int</articleTargetQty>
<articleMinQty>int</articleMinQty>
<articleMaxQty>int</articleMaxQty>
<articleIntervalQty>int</articleIntervalQty>
</OrderingArticleStruct>
</articles>
</OrderingOrderStruct>
</OrderingPointOfServiceStruct>
</pointsOfService>
</OrderingDeliveryAddressStruct>
</deliveryAddresses>
<orderingGroups>
<OrderingOrderingGroupStruct>
<orderingGroupNo>string</orderingGroupNo>
<orderingGroupDescription>string</orderingGroupDescription>
</OrderingOrderingGroupStruct>
<OrderingOrderingGroupStruct>
<orderingGroupNo>string</orderingGroupNo>
<orderingGroupDescription>string</orderingGroupDescription>
</OrderingOrderingGroupStruct>
</orderingGroups>
</OrderInfoResult>
</OrderInfoResponse>
示例 API 响应
{
"deliveryAddresses": {
"OrderingDeliveryAddressStruct": {
"deliveryAddressNo": 5710030,
"deliveryAddressName": "UCLH WARDS LINEN",
"pointsOfService": {
"OrderingPointOfServiceStruct": {
"pointOfServiceNo": 3,
"pointOfServiceName": "E02 S1 THE",
"pointOfServiceDescription": "E02 STORE 1 THEATRES / LABOUR",
"pointOfServiceOrderingGroupNo": "571-1",
"orders": {
"OrderingOrderStruct": {
"orderType": "inventory",
"orderDate": "2023-11-02",
"deliveryDate": "2023-11-02",
"orderStatus": 0,
"articles": {
"OrderingArticleStruct": {
"articleNo": 109842,
"articleDescription": "ESSENTIALS TOP SHEET S",
"articleSize": "",
"articleTargetQty": 80,
"articleMinQty": 0,
"articleMaxQty": 0,
"articleIntervalQty": 0
}
}
}
}
}
}
}
},
"orderingGroups": {
"OrderingOrderingGroupStruct": {
"orderingGroupNo": "571-1",
"orderingGroupDescription": "UCLH"
}
}
}
数据类
import com.google.gson.annotations.SerializedName
data class OrderInfo (
@SerializedName("OrderingOrderInfoResponseStruct" ) var OrderingOrderInfoResponseStruct :
OrderingOrderInfoResponseStruct? = OrderingOrderInfoResponseStruct()
)
data class OrderingOrderInfoResponseStruct (
@SerializedName("deliveryAddresses" ) var deliveryAddresses : DeliveryAddresses? =
DeliveryAddresses(),
@SerializedName("orderingGroups" ) var orderingGroups : OrderingGroups? =
OrderingGroups()
)
data class DeliveryAddresses (
@SerializedName("OrderingDeliveryAddressStruct" ) var OrderingDeliveryAddressStruct :
OrderingDeliveryAddressStruct? = OrderingDeliveryAddressStruct()
)
data class OrderingGroups (
@SerializedName("OrderingOrderingGroupStruct" ) var OrderingOrderingGroupStruct :
OrderingOrderingGroupStruct? = OrderingOrderingGroupStruct()
)
data class OrderingDeliveryAddressStruct (
@SerializedName("deliveryAddressNo" ) var deliveryAddressNo : Int? = null,
@SerializedName("deliveryAddressName" ) var deliveryAddressName : String? = null,
@SerializedName("pointsOfService" ) var pointsOfService : PointsOfService? =
PointsOfService()
)
data class OrderingOrderingGroupStruct (
@SerializedName("orderingGroupNo" ) var orderingGroupNo : String? = null,
@SerializedName("orderingGroupDescription" ) var orderingGroupDescription : String? = null
)
data class OrderingPointOfServiceStruct (
@SerializedName("pointOfServiceNo" ) var pointOfServiceNo : Int? =
null,
@SerializedName("pointOfServiceName" ) var pointOfServiceName : String? =
null,
@SerializedName("pointOfServiceDescription" ) var pointOfServiceDescription : String? =
null,
@SerializedName("pointOfServiceOrderingGroupNo" ) var pointOfServiceOrderingGroupNo : String? =
null,
@SerializedName("orders" ) var orders : Orders? =
Orders()
)
data class Orders (
@SerializedName("OrderingOrderStruct" ) var OrderingOrderStruct : OrderingOrderStruct? =
OrderingOrderStruct()
)
data class OrderingOrderStruct (
@SerializedName("orderType" ) var orderType : String? = null,
@SerializedName("orderDate" ) var orderDate : String? = null,
@SerializedName("deliveryDate" ) var deliveryDate : String? = null,
@SerializedName("orderStatus" ) var orderStatus : Int? = null,
@SerializedName("articles" ) var articles : Articles? = Articles()
)
data class Articles (
@SerializedName("OrderingArticleStruct" ) var OrderingArticleStruct : OrderingArticleStruct? =
OrderingArticleStruct()
)
data class OrderingArticleStruct (
@SerializedName("articleNo" ) var articleNo : Int? = null,
@SerializedName("articleDescription" ) var articleDescription : String? = null,
@SerializedName("articleSize" ) var articleSize : String? = null,
@SerializedName("articleTargetQty" ) var articleTargetQty : Int? = null,
@SerializedName("articleMinQty" ) var articleMinQty : Int? = null,
@SerializedName("articleMaxQty" ) var articleMaxQty : Int? = null,
@SerializedName("articleIntervalQty" ) var articleIntervalQty : Int? = null
)
接口
interface OrderInfoInterface {
@Headers("Content-Type: application/json; charset=utf-8")
@POST("OrderInfo/")
suspend fun getOrderInfo(@Body orderInfoRequest: OrderingRequest):
Response<OrderInfo>
companion object{
fun getApi(): OrderInfoInterface? {
return ApiClient.client?.create(OrderInfoInterface::class.java)
}
}
}
Api 客户端
object ApiClient {
private val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
private val logger = HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY)
private val mOkHttpClient = OkHttpClient.Builder()
.addInterceptor(logger)
.connectTimeout(Duration.ZERO)
.writeTimeout(5, TimeUnit.MINUTES)
.readTimeout(5, TimeUnit.MINUTES)
.build()
var mRetrofit: Retrofit? = null
val client: Retrofit?
get() {
if (mRetrofit == null) {
mRetrofit = Retrofit.Builder()
.baseUrl(BASE_URL)
.client(mOkHttpClient)
//.addConverterFactory(GsonConverterFactory.create(gson))
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
}
return mRetrofit
}
}
存储 库
class DeliveryAddressRepository{
suspend fun getOrderInfoData(sessionKey: OrderingRequest): Response<OrderInfo>?{
return OrderInfoInterface.getApi()?.getOrderInfo(sessionKey)
}
}
视图模型
class LoginViewModel(application: Application) : AndroidViewModel(application) {
private val _sessionKey = MutableLiveData<String?>()
private val _message = MutableLiveData<String?>()
private val userRepo = DeliveryAddressRepository()
val sessionKey: MutableLiveData<String?>
get() = _sessionKey
val message: MutableLiveData<String?>
get() = _message
val loginResult: MutableLiveData<BaseResponse<OrderInfo>> = MutableLiveData()
fun getOrderingData(orderSessionKey: OrderingRequest) {
viewModelScope.launch {
try {
val response = userRepo.getOrderInfoData(orderSessionKey)
if (response?.code() == 200) {
loginResult.value = BaseResponse.Success(response.body())
} else {
loginResult.value = BaseResponse.Error(response?.message())
}
} catch (ex: Exception) {
loginResult.value = BaseResponse.Error(ex.message)
}
}
}
fun getSessionKey(loginRequest: LoginRequest) {
viewModelScope.launch {
val response = LoginApi.retrofitService.getSessionKey(
LoginRequest(loginRequest.username, loginRequest.password)
)
_sessionKey.value = response.sessionKey
_message.value = response.message
}
}
fun getDate(): String? {
val formatter = DateTimeFormatter.ofPattern("EEEE, MMMM, dd, yyyy")
return LocalDateTime.now().format(formatter)
}
}
我的 Fragment 中的 ViewModel 调用
class LoginFragment : Fragment() {
private lateinit var binding: FragmentLoginBinding
private val sharedViewModel: ParamsViewModel by activityViewModels()
private val loginViewModel: LoginViewModel by lazy {
ViewModelProvider(this)[LoginViewModel::class.java]
}
private var username: Editable? = null
private var password: Editable? = null
private var sessionKey = ""
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_login, container, false)
val view = binding.root
sharedViewModel.setAppVersion(BuildConfig.VERSION_NAME)
sharedViewModel.setFlavor(BuildConfig.FLAVOR)
binding.apply { viewModel = loginViewModel }
binding.apply { paramViewModel = sharedViewModel }
binding.lifecycleOwner = this
return view
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// sets Today's date for login activity
binding.date.text = loginViewModel.getDate()
sharedViewModel.setOrderDate(binding.date.text.toString())
sharedViewModel.setAppVersion(BuildConfig.VERSION_NAME)
sharedViewModel.setFlavor(BuildConfig.FLAVOR)
// sets Flavor banner details for login activity
setFlavorBanner()
// initiates Firebase remote config options
fireBaseRemoteConfig()
with(binding) {
loginButton.setOnClickListener {
view
if (checkUsernamePassword()) {
val login = LoginRequest(username.text.toString(), password.text.toString())
loginViewModel.getSessionKey(loginRequest = login)
val orderInfoRequest = OrderingRequest()
loginViewModel.getOrderingData(orderInfoRequest)
binding.lifecycleOwner?.let { it1 ->
loginViewModel.loginResult.observe(it1) {
when (it) {
is BaseResponse.Loading -> {
Toast.makeText(
activity,
"Loading Data",
Toast.LENGTH_LONG
).show()
}
is BaseResponse.Success -> {
Toast.makeText(
activity,
it.data?.OrderingOrderInfoResponseStruct.toString(),
Toast.LENGTH_LONG
).show()
findNavController().navigate(R.id.action_loginFragment_to_landingPageFragment)
}
is BaseResponse.Error -> {
Toast.makeText(
activity,
it.msg,
Toast.LENGTH_LONG
).show()
}
}
}
private fun setFlavorBanner() {
val flavorBanner = binding.flavorBanner
// sets banner text
if (sharedViewModel.flavor.value == "dev") {
flavorBanner.text = resources.getString(R.string.devFlavorText)
}
// hides banner if PROD application
if (sharedViewModel.flavor.value == "prod") {
flavorBanner.isVisible = false;
}
// sets banner text and banner color
if (sharedViewModel.flavor.value == "preProd") {
flavorBanner.text = resources.getString(R.string.testFlavorText)
flavorBanner.run {
setBackgroundColor(
ContextCompat.getColor(
context,
R.color.elis_orange
)
)
}
}
}
private fun fireBaseRemoteConfig() {
// sets the Firebase Remote Config settings
val remoteConfig: FirebaseRemoteConfig = Firebase.remoteConfig
val configSettings = remoteConfigSettings {
minimumFetchIntervalInSeconds = 3600
}
remoteConfig.setConfigSettingsAsync(configSettings)
remoteConfig.setDefaultsAsync(R.xml.remote_config_defaults)
// Fetches remote config parameters setup in the Firebase console.
remoteConfig.fetchAndActivate()
}
private fun checkUsernamePassword(): Boolean {
username = binding.username.text
password = binding.password.text
return if (TextUtils.isEmpty(binding.username.text) ||
TextUtils.isEmpty(binding.password.text)
) {
Toast.makeText(activity, "Username or Password cannot be empty", Toast.LENGTH_LONG)
.show();
false
} else
true
}
答: 暂无答案
评论
OrderingOrderInfoResponseStruct
OrderInfo
deliveryAddresses
java.util.List
@SerializedName