首页 > 解决方案 > 具有具体泛型的内联函数在后台服务中使用时抛出非法类型变量引用异常

问题描述

我有一个使用如下的具体泛型的内联函数。它位于伴随对象内部,因此是静态的:

inline fun <reified T> getListFromPreferences(preferences : SharedPreferences, key : String)
        : MutableList<T> {
            return try {
                val listAsString = preferences.getString(key, "")
                val type: Type = object : TypeToken<List<T>>() {}.type
                val gson = SMSApi.gson
                gson.fromJson<ArrayList<T>>(listAsString, type)
                        ?: ArrayList()
            }catch(exception: JsonSyntaxException) {
                ArrayList()
            }
        }

当我使用仪器测试对其进行测试并在应用程序本身中使用它时,它工作得非常好。但是,当我在后台服务中调用该函数时,它会抛出一个致命异常,说它是非法类型变量引用,退出应用程序:

E/AndroidRuntime: FATAL EXCEPTION: Thread-10 
    Process: example.app, PID: 20728 
    java.lang.AssertionError: illegal type variable reference 
        at libcore.reflect.TypeVariableImpl.resolve(TypeVariableImpl.java:111) 
        at libcore.reflect.TypeVariableImpl.getGenericDeclaration(TypeVariableImpl.java:125) 
        at libcore.reflect.TypeVariableImpl.hashCode(TypeVariableImpl.java:47) 
        at com.google.gson.internal.$Gson$Types$WildcardTypeImpl.hashCode($Gson$Types.java:595) 
        at java.util.Arrays.hashCode(Arrays.java:4074) 
        at com.google.gson.internal.$Gson$Types$ParameterizedTypeImpl.hashCode($Gson$Types.java:502) 
        at com.google.gson.reflect.TypeToken.<init>(TypeToken.java:64) 
        at example.app.NotificationService$remoteNotificationReceived$$inlined$let$lambda$1$1.<init>(PreferenceHelper.kt:16) 
        at example.app.NotificationService$remoteNotificationReceived$$inlined$let$lambda$1.run(NotificationService.kt:63) 
        at java.lang.Thread.run(Thread.java:764)
inline fun <reified T> getListFromPreferences(preferences : SharedPreferences, key : String)
        : MutableList<T> {
            return try {
                val listAsString = preferences.getString(key, "")
                val type: Type = object : TypeToken<List<T>>() {}.type
                val gson = SMSApi.gson
                gson.fromJson<ArrayList<T>>(listAsString, type)
                        ?: ArrayList()
            }catch(exception: JsonSyntaxException) {
                ArrayList()
            }
        }

后台服务是实现 OneSignal 的 OSRemoteNotificationReceivedHandler 的 NotificationService。该函数在 onNotificationReceived() 方法中引发异常。有什么我不明白的原因,为什么在应用程序(前台)中内联很好,但在后台抛出异常?或者有什么办法解决这个问题?

编辑:共享notificationService,调用它:

class NotificationService : OneSignal.OSRemoteNotificationReceivedHandler {
    override fun remoteNotificationReceived(context: Context?, notificationReceivedEvent: OSNotificationReceivedEvent?) {
        notificationReceivedEvent?.let {
            val data = notificationReceivedEvent.notification.additionalData
            if(context != null) {
                //Fetch some vals
                Thread {
                    val result = //Insert data in db
                    //-1 will be returned, for rows that are not inserted.
                    //Rows will not be inserted, if they hurt a unique constraint.
                    //Therefore the following code should only be executed, when it is inserted.
                    if(result[0]!=-1L) {
                    //Get preferences, create item    
                    val list = PreferenceHelper
                            .getListFromPreferences<MessageAcknowledgement> 
                        (preferences, App.ACKNOWLEDGE_IDS) -> throws error
                    list.add(acknowledgeMessage)
                    PreferenceHelper.setListInPreferences(preferences, 
                    App.ACKNOWLEDGE_IDS, list)
                    //Do some more stuff
                    }
                }.start()
            }
            Log.d("NotificationService", data.toString())          
  notificationReceivedEvent.complete(notificationReceivedEvent.notification)
        }
    }
}

标签: kotlingenericsexceptionbackground-servicekotlin-reified-type-parameters

解决方案


我不确定上面的代码有什么问题,它需要分享更多,但 Kotlin 有一种获取Type令牌的本机方式。只需更换:

object : TypeToken<List<T>>() {}.type

和:

typeOf<List<T>>().javaType

由于typeOf()仍处于试验阶段,您需要使用以下内容注释您的函数:@OptIn(ExperimentalStdlibApi::class)。我已经使用了一段时间并且从未遇到任何问题,所以我想它使用起来非常安全,至少在 JVM 上是这样。


推荐阅读