我正在做一个Jetpack Compose的小项目。我试图从静态JSON文件的数据从这个url使用Retrofit。https://firebasestorage.googleapis.com/v0/b/culoader.appspot.com/o/json%2Fcudata.json?alt=media&令牌= d0679703 - 2 f6c - 440 f - af03 d4d61305cc84
<网络模块/strong>
@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)
}
}
服务类
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. composer .runtime. mutablestate com.tuts.playlite.net .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,因此可能会得到空异常。不知道为什么要添加随机文本!
您已经为retrofit提供了一个Gson转换器,因此retrofit应该已经能够为您进行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,但我猜你正在寻找mutableelvedata或MutableStateFlow。下面是一个使用mutableelvedata的例子:
@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使用这个存储库类
suspend fun getCurrencyFile:Response<CurrencyAPIResponse>{
return currencyService.getCurrencyFile()
}
然后在视图模型类
中Coroutines.main {
try{
val response = repository.getCurrencyFile()
if(response.isSuccessful){
//response.body is your data
}
}catch(Exception){}
}
如果你不使用存储库类,你可以跳过第二步,直接调用viewmodel类中的服务。协程代码为
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)
感谢大家的支持!