Retrofit获取数据为空问题排查求助(附完整代码)
货币应用Retrofit请求数据为空排查
我正在开发一款货币类应用,使用Retrofit接口请求数据时,收到的是空数据,但返回的JSON格式是正常的。调试后无法定位错误位置及原因,附上所有相关代码,希望能得到帮助排查问题。
相关代码
ApiService
interface ApiService { @GET("daily_json.js") suspend fun getValute(): Response<Valute> }
RetrofitInstance
object RetrofitInstance { private val retrofit by lazy { Retrofit.Builder().baseUrl("https://www.cbr-xml-daily.ru/") .addConverterFactory(GsonConverterFactory.create()) .build() } val api: ApiService by lazy { retrofit.create(ApiService::class.java) } }
Repository
class Repository { suspend fun getVal(): Response<Valute>{ return RetrofitInstance.api.getValute() } }
ViewModel
class StartViewModel: ViewModel() { var repo = Repository() val moneyList: MutableLiveData<Response<Valute>> = MutableLiveData() fun getMoney(){ viewModelScope.launch { moneyList.value = repo.getVal() } } }
Fragment
class StartFragment : Fragment() { private lateinit var _binding: FragmentStartBinding private val binding get() = _binding!! private val adapter = StartAdapter() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { _binding = FragmentStartBinding.inflate(inflater, container, false) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) binding.rvStart.adapter = adapter val viewModel = ViewModelProvider(this).get(StartViewModel::class.java) viewModel.getMoney() viewModel.moneyList.observe(viewLifecycleOwner,{list -> list.body()?.let { adapter.setList(it) } }) } }
Adapter
class StartAdapter: RecyclerView.Adapter<StartAdapter.StartHolder>() { var listValute = emptyList<Valute>() class StartHolder(item: View): RecyclerView.ViewHolder(item) { val binding = ItemBinding.bind(item) fun bind(valute: Valute) = with(binding){ nameMoney.text = valute.CharCode purchase.text = valute.Value.toString() } } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StartHolder { val view = LayoutInflater.from(parent.context).inflate(R.layout.item, parent, false) return StartHolder(view) } override fun getItemCount(): Int { return listValute.size } override fun onBindViewHolder(holder: StartHolder, position: Int) { holder.bind(listValute[position]) } fun setList(valute: Valute){ listValute = listOf(valute) notifyDataSetChanged() } }
补充数据类
data class Valute( val CharCode: String, val ID: String, val Name: String, val Nominal: Int, val NumCode: String, val Previous: Double, val Value: Double ): Serializable
问题排查与修复
核心错误点
- JSON结构不匹配:目标接口
https://www.cbr-xml-daily.ru/daily_json.js的返回外层是一个包含Valute字段的对象,Valute内部是多个货币的键值对(如USD、EUR对应单个Valute实例),但你的接口直接声明返回Response<Valute>,Gson无法将整个JSON解析为单个Valute对象,导致解析后数据为空。 - Adapter数据处理错误:即使拿到正确数据,你的
setList方法将单个Valute转为列表,而实际需要的是多个Valute的集合,RecyclerView无法正确展示数据。
修复步骤
1. 新增外层数据类匹配JSON结构
data class CurrencyResponse( val Date: String, val PreviousDate: String, val PreviousURL: String, val Timestamp: String, val Valute: Map<String, Valute> ): Serializable
2. 修改ApiService返回类型
interface ApiService { @GET("daily_json.js") suspend fun getValute(): Response<CurrencyResponse> }
3. 更新Repository和ViewModel的返回类型
Repository:
class Repository { suspend fun getVal(): Response<CurrencyResponse>{ return RetrofitInstance.api.getValute() } }
ViewModel:
class StartViewModel: ViewModel() { var repo = Repository() val moneyList: MutableLiveData<Response<CurrencyResponse>> = MutableLiveData() fun getMoney(){ viewModelScope.launch { moneyList.value = repo.getVal() } } }
4. 调整Fragment的数据解析逻辑
将Valute的Map转为List传给Adapter:
viewModel.moneyList.observe(viewLifecycleOwner, { response -> response.body()?.let { currencyResponse -> val valuteList = currencyResponse.Valute.values.toList() adapter.setList(valuteList) } })
5. 修改Adapter的setList方法
fun setList(valuteList: List<Valute>){ listValute = valuteList notifyDataSetChanged() }
额外调试建议
- 在Fragment中打印
response.body()的内容,确认解析后的数据是否正确 - 添加Retrofit日志拦截器,查看实际请求的返回内容,验证是否与预期一致
内容的提问来源于stack exchange,提问作者Vlad Tkachev
相关产品推荐
相关产品推荐

