Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Gson无法在我的Android&;中调用no-args construktor for observer(LiveData);科特林项目_Android_Kotlin_Gson_Android Room_Android Livedata - Fatal编程技术网

Gson无法在我的Android&;中调用no-args construktor for observer(LiveData);科特林项目

Gson无法在我的Android&;中调用no-args construktor for observer(LiveData);科特林项目,android,kotlin,gson,android-room,android-livedata,Android,Kotlin,Gson,Android Room,Android Livedata,我已经读了很多stackoverflow的文章和其他关于它的博客文章,它们尝试了不同的解决方案来解决类似(但不相同)的问题 我将按如下方式安排这一职位: 我的问题 我的代码(我认为相关的部分) 我试图修复的是什么 1.我的问题 我收到以下错误消息: Process: com.myapp, PID: 23553 java.lang.RuntimeException: Unable to invoke no-args constructor for androidx.arch.cor

我已经读了很多stackoverflow的文章和其他关于它的博客文章,它们尝试了不同的解决方案来解决类似(但不相同)的问题

我将按如下方式安排这一职位:

  • 我的问题
  • 我的代码(我认为相关的部分)
  • 我试图修复的是什么
  • 1.我的问题 我收到以下错误消息:

        Process: com.myapp, PID: 23553
        java.lang.RuntimeException: Unable to invoke no-args constructor for androidx.arch.core.internal.SafeIterableMap$SupportRemove<androidx.lifecycle.Observer<? super java.lang.Integer>, androidx.lifecycle.LiveData$ObserverWrapper>. Registering an InstanceCreator with Gson for this type may fix this problem.
            at com.google.gson.internal.ConstructorConstructor$14.construct(ConstructorConstructor.java:228)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:212)
            at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:41)
            at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:186)
            at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:145)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131)
            at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222)
            at com.google.gson.Gson.fromJson(Gson.java:932)
            at com.google.gson.Gson.fromJson(Gson.java:897)
            at com.google.gson.Gson.fromJson(Gson.java:846)
            at com.myapp.ui.customGame.CustomGameViewModel.initialize(CustomGameViewModel.kt:46)
    
    道:

    package com.myapp.data
    
    import androidx.room.*
    
    @Dao
    interface GameDao {
        @Query("SELECT * FROM gameData_table")
        suspend fun getAll(): List<GameData>
    
        @Query("SELECT * FROM gameData_table WHERE id = (:id)")
        fun loadAllByIds(id: Array<Int>): List<GameData>
    
        @Query("SELECT * FROM gameData_table WHERE is_over = 0")
        suspend fun getOngoing() : List<GameData>
    
        @Insert(onConflict = OnConflictStrategy.REPLACE)
        suspend fun insertAll(vararg game: GameData)
    
        @Delete
        suspend fun delete(game: GameData)
    
        @Query("DELETE FROM gameData_table WHERE is_over = 0")
        suspend fun deleteOngoing()
    
        @Query("UPDATE gameData_table SET game_json = (:json) WHERE gid = (:gameId)")
        suspend fun updateJSON(json: String, gameId : String)
    }
    
    存储库:

    package com.myapp.data
    
    import kotlinx.coroutines.runBlocking
    
    class GameRepository (private val gameDao: GameDao){
        val allGameData: List<GameData> = runBlocking { gameDao.getAll()}
        val ongoingGameData : List<GameData> = runBlocking { gameDao.getOngoing() }
    
        suspend fun insert(gameData : GameData){
            gameDao.insertAll(gameData)
        }
    
        suspend fun deleteOngoing() {
            gameDao.deleteOngoing()
        }
    
        suspend fun updateGame(gameData : GameData){
            gameDao.updateJSON(gameData.gameJson!!, gameData.gid!!)
        }
    
    }
    
    package com.myapp.data
    导入kotlinx.coroutines.runBlocking
    类GameRepository(私有val gameDao:gameDao){
    val allGameData:List=runBlocking{gameDao.getAll()}
    val-ongoingGameData:List=runBlocking{gameDao.getContinuous()}
    暂停趣味插入(gameData:gameData){
    gameDao.insertAll(gameData)
    }
    暂停(正在进行的){
    gameDao.deleteDao()
    }
    暂停趣味更新游戏(gameData:gameData){
    gameDao.updateJSON(gameData.gameJson!!,gameData.gid!!)
    }
    }
    
    b) 游戏课 现在是一个非常简短的游戏版本,因为大多数方法都与我的问题无关,我认为:

    package com.myapp.game
    
    import android.app.Application
    import androidx.lifecycle.LiveData
    import androidx.lifecycle.MutableLiveData
    import com.myapp.data.GameData
    import com.myapp.values.Values
    import com.google.gson.Gson
    
    class Game {
    
    
        /*
        No live data needed or possible?
         */
        private var sets : MutableList<Set>
        private val pointGap : Int = Values.DEFAULT_POINT_GAP
        private val gid : String = this.toString()
    
        /*
        Live data needed or possible
         */
    
        // private MutableLiveData
        private var _team1Name : MutableLiveData<String> = MutableLiveData(Values.DEFAULT_TEAM1_NAME)
        (more strings ...)
        private var _setWinScore : MutableLiveData<Int> = MutableLiveData(Values.DEFAULT_WIN_SCORE)
        (...)
    
        // public LiveData
        val team1Name : LiveData<String>
        (more strings ...)
        val setWinScore : LiveData<Int>
        (...)
    
    
        init{
            team1Name = _team1Name
            (more strings ...)
            setWinScore = _setWinScore
            (...)
    
        }
    
    
        constructor(gameSettings: GameSettings = GameSettings()){
            this._team1Name.value = gameSettings.team1Name
            (more strings...)
            this._setWinScore.value = gameSettings.setWinScore
            (...)
        }
    }
    
    package com.myapp.game
    导入android.app.Application
    导入androidx.lifecycle.LiveData
    导入androidx.lifecycle.MutableLiveData
    导入com.myapp.data.GameData
    导入com.myapp.values.values
    导入com.google.gson.gson
    班级游戏{
    /*
    不需要或可能没有实时数据?
    */
    私有变量集:可变列表
    private val pointGap:Int=Values.DEFAULT_POINT_GAP
    private val gid:String=this.toString()
    /*
    需要或可能需要实时数据
    */
    //私有可变LiveData
    私有var\u team1Name:MutableLiveData=MutableLiveData(value.DEFAULT\u TEAM1\u NAME)
    (更多字符串…)
    私有变量_setWinScore:MutableLiveData=MutableLiveData(value.DEFAULT_WIN_SCORE)
    (...)
    //公共实时数据
    val team1Name:LiveData
    (更多字符串…)
    val setWinScore:LiveData
    (...)
    初始化{
    团队名称=_团队名称
    (更多字符串…)
    setWinScore=_setWinScore
    (...)
    }
    构造函数(gameSettings:gameSettings=gameSettings()){
    这是。_team1Name.value=gameSettings.team1Name
    (更多字符串…)
    这是。_setWinScore.value=gameSettings.setWinScore
    (...)
    }
    }
    
    3.解决方法# 我试着使用InstanceCreator。但是在我读了一些关于它的内容之后,我发现如果您想要重新创建的对象有一个Gson类需要知道的参数,那么这是必要的(例如,上下文)。我想我没有这个(?。
    我试过了,当然没用。 我还尝试了使用TypeToken的几种变体,我在开始时也展示了这些变体

    我经常读到的另一件事是使用最新版本的包Gson、Room和LiveData,或者在项目级的grandle.build中使用kapt instad of implement关键字。 我尝试了两个->相同的异常

    那么,你有什么想法吗? 还是我做错了什么愚蠢的事?
    提前感谢您牺牲您的时间


    PS:我不是英语母语,很抱歉语法和拼写不好。

    下面展示了如何反序列化
    LiveData
    ,但是在您的用例中,可能更适合将
    游戏
    数据作为
    视图模型
    共享?看


    当没有自定义或内置类型适配器匹配时,Gson使用基于反射的适配器。问题在于,您要求Gson将JSON反序列化为
    LiveData
    。如果查看
    LiveData
    的字段,您将看到它有多个私有字段,对于其中一个字段的类型,Gson无法创建实例

    一般来说,不鼓励对任何第三方类(此处为
    LiveData
    )使用Gson基于反射的序列化或反序列化,因为这样您就依赖于它们的内部实现细节,这些细节可能会在任何时候发生变化

    这可以通过创建自定义项来解决。
    我不熟悉Kotlin,但希望以下Java代码对您有用,尽管如此:

    类LiveDataTypeAdapterFactory实现TypeAdapterFactory{
    公共静态最终LiveDataTypeAdapterFactory实例=新的LiveDataTypeAdapterFactory();
    私有LiveDataTypeAdapterFactory(){}
    @凌驾
    公共类型适配器创建(Gson Gson,TypeToken类型){
    类rawType=type.getRawType();
    //仅处理LiveData和MutableLiveData
    if(rawType!=LiveData.class&&rawType!=MutableLiveData.class){
    返回null;
    }
    //假设LiveData从未用作原始类型,但始终是参数化的
    类型valueType=((ParameteredType)类型.getType()).getActualTypeArguments()[0];
    //获取LiveData值类型`T的适配器`
    //转换TypeAdapter以简化下面的适配器代码
    @抑制警告(“未选中”)
    TypeAdapter valueAdapter=(TypeAdapter)gson.getAdapter(TypeToken.get(valueType));
    //由于在方法开始时进行“type”检查,因此是安全的
    @抑制警告(“未选中”)
    TypeAdapter=(TypeAdapter)新的TypeAdapter读取(JsonReader in)引发IOException{
    对象值=valueAdapter.read(在中);
    返回新的可变LiveData(值);
    }
    };
    返回适配器;
    }
    }
    
    (请注意,这不会保留
    LiveData
    的观察者)

    然后,您可以使用创建
    Gson
    实例并注册工厂:

    Gson Gson=new GsonBuilder()
    .registerTypeAdapterFactory(LiveDataTypeAdapterFactory.INSTANCE)
    .create();
    
    反序列化
    游戏
    时不需要使用
    TypeToken
    ,直接使用类也可以<代码>类型标记用于泛型类型

    理想情况下,您还可以创建一个
    TypeAdapterFactorypackage com.myapp.data
    
    import android.content.Context
    import androidx.room.Database
    import androidx.room.Room
    import androidx.room.RoomDatabase
    
    @Database(entities = [GameData::class], version = 1, exportSchema = false)
    abstract class GameDatabase : RoomDatabase() {
        abstract fun gameDao() : GameDao
    
        companion object {
            //Singleton pattern to prevent multiple instances of the database
    
            @Volatile
            private var INSTANCE: GameDatabase? = null
    
            fun getDatabase(context: Context) : GameDatabase {
                return INSTANCE ?: synchronized(this){
                    val instance = Room.databaseBuilder(
                        context.applicationContext,
                        GameDatabase::class.java,
                        "game_database"
                    ).build()
    
                    INSTANCE = instance
                    return instance
                }
            }
        }
    
    package com.myapp.data
    
    import kotlinx.coroutines.runBlocking
    
    class GameRepository (private val gameDao: GameDao){
        val allGameData: List<GameData> = runBlocking { gameDao.getAll()}
        val ongoingGameData : List<GameData> = runBlocking { gameDao.getOngoing() }
    
        suspend fun insert(gameData : GameData){
            gameDao.insertAll(gameData)
        }
    
        suspend fun deleteOngoing() {
            gameDao.deleteOngoing()
        }
    
        suspend fun updateGame(gameData : GameData){
            gameDao.updateJSON(gameData.gameJson!!, gameData.gid!!)
        }
    
    }
    
    package com.myapp.game
    
    import android.app.Application
    import androidx.lifecycle.LiveData
    import androidx.lifecycle.MutableLiveData
    import com.myapp.data.GameData
    import com.myapp.values.Values
    import com.google.gson.Gson
    
    class Game {
    
    
        /*
        No live data needed or possible?
         */
        private var sets : MutableList<Set>
        private val pointGap : Int = Values.DEFAULT_POINT_GAP
        private val gid : String = this.toString()
    
        /*
        Live data needed or possible
         */
    
        // private MutableLiveData
        private var _team1Name : MutableLiveData<String> = MutableLiveData(Values.DEFAULT_TEAM1_NAME)
        (more strings ...)
        private var _setWinScore : MutableLiveData<Int> = MutableLiveData(Values.DEFAULT_WIN_SCORE)
        (...)
    
        // public LiveData
        val team1Name : LiveData<String>
        (more strings ...)
        val setWinScore : LiveData<Int>
        (...)
    
    
        init{
            team1Name = _team1Name
            (more strings ...)
            setWinScore = _setWinScore
            (...)
    
        }
    
    
        constructor(gameSettings: GameSettings = GameSettings()){
            this._team1Name.value = gameSettings.team1Name
            (more strings...)
            this._setWinScore.value = gameSettings.setWinScore
            (...)
        }
    }