我正在尝试使用Gson库将Kotlin类的实例存储到JSON文件中。但是,当我运行Gson()。fromJson时,出现以下错误:
java.lang.RuntimeException: Failed to invoke public com.keikakupet.PetStatus() with no args
我对错误的理解是Gson要求我的类具有不带任何参数的主构造函数,以便可以构造所需的对象(在这种情况下为PetStatus对象)。但是,我有这样的构造函数。我不确定部分问题是否在于我正在从init运行方法的事实。有谁知道我该如何解决这个错误?
我的代码:
package com.keikakupet
import android.content.Context
import android.util.Log
import com.google.gson.Gson
import java.io.File
import java.util.*
import java.io.BufferedReader
class PetStatus constructor(){
var maxHealth: Int = 10
var currentHealth: Int = 10
var healthIncrementer: Int = 2 // amount by which health increments when a task is completed
var healthDecrementer: Int = 0 // amount by which health decrements when user approaches / misses deadline
var isHungry: Boolean = false
var isTired: Boolean = false
var isSick: Boolean = false
var isAlive: Boolean = true
init{
//if a json exists, use it to update PetStatus
val context = getContext()
var file = File(context.getFilesDir(), "PetStatus.json")
if(file.exists()){
Log.d("FILE_EXISTS", "File exists!")
val bufferedReader: BufferedReader = file.bufferedReader()
val json = bufferedReader.readText()
val retrievedStatus = Gson().fromJson(json, PetStatus::class.java)
Log.d("JSON_RETRIEVED", json)
}
else
Log.d("FILE_DNE", "File does not exist!")
updateJson()
}
// method to update pet's health and ailment upon completing a task
fun processCompletedTask(){
incrementHealth()
removeAilment()
Log.d("TASK_COMPLETE", "completed task processed")
}
fun getHealthPercent(): Int {
return currentHealth / maxHealth
}
// method to update pet's health and ailment upon missing a task
fun processMissedTask(){
decrementHealth()
addAilment()
Log.d("TASK_MISSED", "missed task processed")
}
/*
Potentially creating another method to update pet's
health and status because of an approaching deadline.
*/
// method to decrement the pet's health
private fun decrementHealth(){
currentHealth-=healthDecrementer
if(currentHealth <= 0)
isAlive = false
updateJson()
}
// method to increment the pet's health
private fun incrementHealth(){
val sum = currentHealth + healthIncrementer
if(sum > maxHealth)
currentHealth = maxHealth
else
currentHealth = sum
updateJson()
}
// method to add an ailment to the pet
private fun addAilment(){
// if no ailment, randomly assign hungry or tired
if(!isHungry && !isTired && !isSick){
val rand = Random()
val randBool = rand.nextBoolean()
if(randBool)
isHungry = true
else
isTired = true
healthDecrementer = 1
}
// otherwise, if hungry XOR tired, assign the other
else if(isHungry && !isTired){
isTired = true
healthDecrementer = 2
}
else if(isTired && !isHungry){
isHungry = true
healthDecrementer = 2
}
// otherwise, if both hungry AND tired, assign sick
else if(isHungry && isTired){
isSick = true
healthDecrementer = 3
}
updateJson()
}
// method to remove an ailment from the pet
private fun removeAilment(){
// if sick, remove sick
if(isSick){
isSick = false
healthDecrementer = 2
}
// otherwise, if hungry and tired, remove one of the two randomly
else if(isHungry && isTired){
val rand = Random()
val randBool = rand.nextBoolean()
if(randBool)
isHungry = false
else
isTired = false
healthDecrementer = 1
}
// otherwise, if hungry XOR tired, remove relevant ailment
else if(isHungry && !isTired){
isHungry = false
healthDecrementer = 0
}
else if(isTired){
isTired = false
healthDecrementer = 0
}
updateJson()
}
private fun updateJson(){
val gson = Gson()
var json: String = gson.toJson(this)
Log.d("JSON_UPDATE", json)
val context = getContext()
var file = File(context.getFilesDir(), "PetStatus.json")
file.writeText(json)
val bufferedReader: BufferedReader = file.bufferedReader()
json = bufferedReader.readText()
Log.d("JSON_FROM_FILE", json)
}
companion object {
private lateinit var context: Context
fun setContext(con: Context) {
context=con
}
fun getContext() : Context {
return context
}
}
}
Logcat信息:
Caused by: java.lang.RuntimeException: Failed to invoke public com.keikakupet.PetStatus() with no args
at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:118)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:212)
at com.google.gson.Gson.fromJson(Gson.java:927)
at com.google.gson.Gson.fromJson(Gson.java:892)
at com.google.gson.Gson.fromJson(Gson.java:841)
at com.google.gson.Gson.fromJson(Gson.java:813)
at com.keikakupet.PetStatus.<init>(PetStatus.kt:32)
at java.lang.reflect.Constructor.newInstance0(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
at com.google.gson.internal.ConstructorConstructor$3.construct(ConstructorConstructor.java:110)
... 4981 more
最佳答案
由于您的构造函数没有参数,因此Gson无法在json的帮助下实例化您的类。
像这样重组您的类(class):
class PetStatus private constructor(
var maxHealth: Int = 10,
var currentHealth: Int = 10,
var healthIncrementer: Int = 2, // amount by which health increments when a task is completed
var healthDecrementer: Int = 0, // amount by which health decrements when user approaches / misses deadline
var isHungry: Boolean = false,
var isTired: Boolean = false,
var isSick: Boolean = false,
var isAlive: Boolean = true) {
/**
* This is optional fix, since it is a design guideline
* recommendation, you can retain your original function as well
* fun getHealthPercent(): Int {
* return currentHealth / maxHealth
* }
*/
val healthPercent: Int
get() = currentHealth / maxHealth
...
companion object {
lateinit var context: Context // getters and setters for java are automatically generated
operator fun invoke(): PetStatus {
//if a json exists, use it to update PetStatus
val context = context
var file = File(context.getFilesDir(), "PetStatus.json")
if(file.exists()){
Log.d("FILE_EXISTS", "File exists!")
val bufferedReader: BufferedReader = file.bufferedReader()
val json = bufferedReader.readText()
val retrievedStatus = Gson().fromJson(json, PetStatus::class.java)
Log.d("JSON_RETRIEVED", json)
return retrievedStatus
} else {
Log.d("FILE_DNE", "File does not exist!")
return PetStatus()
}
updateJson()
}
operator fun invoke(maxHealth: Int, currentHealth: Int, healthIncrementer: Int, healthDecrementer: Int, isHungry: Boolean, isTired: Boolean, isSick: Boolean, isAlive: Boolean): PetStatus
= PetStatus(maxHealth, currentHealth, healthIncrementer, healthDecrementer, isHungry, isTired, isSick, isAlive)
}
}
现在您可以将类(class)命名为相同
PetStatus()
operator fun invoke()
是一种破解方法,我建议您实际上应该将代码取出并从外部实例化该类。
关于android-studio - Gson()。fromJson错误- “Failed to invoke public com.keikakupet.PetStatus() with no args”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61181225/