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

Inline function with reified generic throws illegal type variable reference exception when used in background service

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

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.<init>(PreferenceHelper.kt:16) 
        at example.app.NotificationService$remoteNotificationReceived$$inlined$let$lambda.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)
        }
    }
}

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

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

与:

typeOf<List<T>>().javaType

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