无法从 Retrofit Call 获取数据到直接 JSON 文件
Unable to get data from Retrofit Call to a Direct JSON File
我正在使用 Jetpack Compose 开发一个小项目。
我正在尝试使用 Retrofit 来自此 url 的静态 JSON 文件中的数据。
https://firebasestorage.googleapis.com/v0/b/culoader.appspot.com/o/json%2Fcudata.json?alt=media&token=d0679703-2f6c-440f-af03-d4d61305cc84
网络模块
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
@Singleton
fun proveidesCurrencyService() : CurrencyService{
return Retrofit.Builder()
.baseUrl("https://firebasestorage.googleapis.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(CurrencyService::class.java)
}
}
服务Class
interface CurrencyService {
//@Streaming
@GET
suspend fun getCurrencyFile(@Url fileUrl:String): Response<ResponseBody>
}
data class CurrencyAPIResponse(
@SerializedName("data") var data: MutableState<List<CurrencyRates>>
)
data class CurrencyRates (
@SerializedName("code") var code : String,
@SerializedName("value") var value : String
)
ViewModel
@HiltViewModel
class CurrencyDataViewModel
@Inject
constructor(private val currencyService: CurrencyService
) : ViewModel()
{
init {
getCurrencyFileData()
}
}
fun getCurrencyFileData() = viewModelScope.launch(Dispatchers.IO) {
val url: String =
"https://firebasestorage.googleapis.com/v0/b/culoader.appspot.com/o/json%2Fcudata.json?alt=media&token=d0679703-2f6c-440f-af03-d4d61305cc84"
val responseBody = currencyService.getCurrencyFile(url).body()
if (responseBody != null) {
Log.d("\nresponsebody", responseBody.string())
val gson = GsonBuilder().setPrettyPrinting().create()
val currencyAPIResponse = gson.fromJson(responseBody.string(), CurrencyAPIResponse::class.java)
val data: MutableState<List<CurrencyRates>> = currencyAPIResponse.data
Log.d("Data", data.value[0].code)
}
}
每次,我都会收到以下错误,
尝试在空对象引用上调用虚方法'androidx.compose.runtime.MutableState com.tuts.playlite.network.response.CurrencyAPIResponse.getData()'
不确定,在我失败的地方,我尝试将其转换为 JSON 对象,但仍然失败。获取数据的方式是否正确?
另一件事注意到,即使 JSON 文件在 url 中是完整的,响应正文日志显示 JSON 和一些其他内容。
{
"code": "IMP",
"value": "0.722603"
},
{
"code": "INR",
[ 1631385414.170 12452:12478 D/
responsebody]
"value": "72.99465"
},
{
"code": "IQD",
"value": "1458.61356"
},
因此,GSON 可能无法形成 json,因此可能会出现空异常。
不确定为什么会添加随机文本!
您已经提供了一个 Gson 转换器进行改造,因此改造应该已经能够为您完成 json 到对象的转换。这就是改造之美!
尝试像这样重写您的 CurrencyService:
interface CurrencyService {
@GET("v0/b/culoader.appspot.com/o/json%2Fcudata.json?alt=media&token=d0679703-2f6c-440f-af03-d4d61305cc84")
suspend fun getCurrencyFile(): CurrencyAPIResponse
}
您的 ViewModel 也有一些问题。不确定您是否真正指的是 MutableState,但我猜您正在寻找 MutableLiveData 或 MutableStateFlow。下面是一个使用 MutableLiveData 的例子。
@HiltViewModel
class CurrencyDataViewModel @Injectconstructor(
private val currencyService: CurrencyService
) : ViewModel() {
private val _currencyData = MutableLiveData<List<CurrencyRates>>()
private val currencyData: LiveData = _currencyData
init {
getCurrencyFileData()
}
fun getCurrencyFileData() = viewModelScope.launch(Dispatchers.IO) {
_currencyData.postValue(currencyService.getCurrencyFile().data)
}
}
使用 Kotin Coroutines 进行改造,试试下面的方法
interface CurrencyService {
@GET("v0/b/culoader.appspot.com/o/json%2Fcudata.json?alt=media&token=d0679703-2f6c-440f-af03-d4d61305cc84")
suspend fun getCurrencyFile(): Response<CurrencyAPIResponse>
}
如果您使用的是 MVVM,请使用此存储库 class
suspend fun getCurrencyFile:Response<CurrencyAPIResponse>{
return currencyService.getCurrencyFile()
}
然后在您的视图模型中 class
Coroutines.main {
try{
val response = repository.getCurrencyFile()
if(response.isSuccessful){
//response.body is your data
}
}catch(Exception){}
}
如果你没有使用存储库class你可以跳过第二步直接在viewmodel中调用服务class,
协程代码是
object Coroutines {
fun main(work:suspend (()->Unit)) =
CoroutineScope(Dispatchers.Main).launch {
work()
}
}
最后,罪魁祸首似乎是responseBody Stream。在我用下面更改代码后,它似乎可以正常工作。我假设,它无法更早地获得正确的完整 JSON 并抛出空对象引用错误。
val responseBody = currencyService.getCurrencyFile(url).body()
val resData = responseBody?.byteStream()!!.bufferedReader().use {
it.readText()
}
val gson = GsonBuilder().setPrettyPrinting().create()
val currencyAPIResponse = gson.fromJson(resData, CurrencyAPIResponse::class.java)
感谢大家的支持!
我正在使用 Jetpack Compose 开发一个小项目。 我正在尝试使用 Retrofit 来自此 url 的静态 JSON 文件中的数据。 https://firebasestorage.googleapis.com/v0/b/culoader.appspot.com/o/json%2Fcudata.json?alt=media&token=d0679703-2f6c-440f-af03-d4d61305cc84
网络模块
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
@Singleton
fun proveidesCurrencyService() : CurrencyService{
return Retrofit.Builder()
.baseUrl("https://firebasestorage.googleapis.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(CurrencyService::class.java)
}
}
服务Class
interface CurrencyService {
//@Streaming
@GET
suspend fun getCurrencyFile(@Url fileUrl:String): Response<ResponseBody>
}
data class CurrencyAPIResponse(
@SerializedName("data") var data: MutableState<List<CurrencyRates>>
)
data class CurrencyRates (
@SerializedName("code") var code : String,
@SerializedName("value") var value : String
)
ViewModel
@HiltViewModel
class CurrencyDataViewModel
@Inject
constructor(private val currencyService: CurrencyService
) : ViewModel()
{
init {
getCurrencyFileData()
}
}
fun getCurrencyFileData() = viewModelScope.launch(Dispatchers.IO) {
val url: String =
"https://firebasestorage.googleapis.com/v0/b/culoader.appspot.com/o/json%2Fcudata.json?alt=media&token=d0679703-2f6c-440f-af03-d4d61305cc84"
val responseBody = currencyService.getCurrencyFile(url).body()
if (responseBody != null) {
Log.d("\nresponsebody", responseBody.string())
val gson = GsonBuilder().setPrettyPrinting().create()
val currencyAPIResponse = gson.fromJson(responseBody.string(), CurrencyAPIResponse::class.java)
val data: MutableState<List<CurrencyRates>> = currencyAPIResponse.data
Log.d("Data", data.value[0].code)
}
}
每次,我都会收到以下错误,
尝试在空对象引用上调用虚方法'androidx.compose.runtime.MutableState com.tuts.playlite.network.response.CurrencyAPIResponse.getData()'
不确定,在我失败的地方,我尝试将其转换为 JSON 对象,但仍然失败。获取数据的方式是否正确?
另一件事注意到,即使 JSON 文件在 url 中是完整的,响应正文日志显示 JSON 和一些其他内容。
{
"code": "IMP",
"value": "0.722603"
},
{
"code": "INR",
[ 1631385414.170 12452:12478 D/
responsebody]
"value": "72.99465"
},
{
"code": "IQD",
"value": "1458.61356"
},
因此,GSON 可能无法形成 json,因此可能会出现空异常。 不确定为什么会添加随机文本!
您已经提供了一个 Gson 转换器进行改造,因此改造应该已经能够为您完成 json 到对象的转换。这就是改造之美!
尝试像这样重写您的 CurrencyService:
interface CurrencyService {
@GET("v0/b/culoader.appspot.com/o/json%2Fcudata.json?alt=media&token=d0679703-2f6c-440f-af03-d4d61305cc84")
suspend fun getCurrencyFile(): CurrencyAPIResponse
}
您的 ViewModel 也有一些问题。不确定您是否真正指的是 MutableState,但我猜您正在寻找 MutableLiveData 或 MutableStateFlow。下面是一个使用 MutableLiveData 的例子。
@HiltViewModel
class CurrencyDataViewModel @Injectconstructor(
private val currencyService: CurrencyService
) : ViewModel() {
private val _currencyData = MutableLiveData<List<CurrencyRates>>()
private val currencyData: LiveData = _currencyData
init {
getCurrencyFileData()
}
fun getCurrencyFileData() = viewModelScope.launch(Dispatchers.IO) {
_currencyData.postValue(currencyService.getCurrencyFile().data)
}
}
使用 Kotin Coroutines 进行改造,试试下面的方法
interface CurrencyService {
@GET("v0/b/culoader.appspot.com/o/json%2Fcudata.json?alt=media&token=d0679703-2f6c-440f-af03-d4d61305cc84")
suspend fun getCurrencyFile(): Response<CurrencyAPIResponse>
}
如果您使用的是 MVVM,请使用此存储库 class
suspend fun getCurrencyFile:Response<CurrencyAPIResponse>{
return currencyService.getCurrencyFile()
}
然后在您的视图模型中 class
Coroutines.main {
try{
val response = repository.getCurrencyFile()
if(response.isSuccessful){
//response.body is your data
}
}catch(Exception){}
}
如果你没有使用存储库class你可以跳过第二步直接在viewmodel中调用服务class, 协程代码是
object Coroutines {
fun main(work:suspend (()->Unit)) =
CoroutineScope(Dispatchers.Main).launch {
work()
}
}
最后,罪魁祸首似乎是responseBody Stream。在我用下面更改代码后,它似乎可以正常工作。我假设,它无法更早地获得正确的完整 JSON 并抛出空对象引用错误。
val responseBody = currencyService.getCurrencyFile(url).body()
val resData = responseBody?.byteStream()!!.bufferedReader().use {
it.readText()
}
val gson = GsonBuilder().setPrettyPrinting().create()
val currencyAPIResponse = gson.fromJson(resData, CurrencyAPIResponse::class.java)
感谢大家的支持!