You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Jetpack DataStore插桩测试中获取Proto字符串列表抛NoClassDefFoundError

Android DataStore Proto Store插桩测试获取List报错排查

我在Android应用的公共模块中将SharedPreferences替换为DataStore,用DataProperty便捷访问参数,同时按需注入MyDataStore接口。因业务需求还实现了proto store,所有功能运行正常,迁移过程顺利,但运行插桩测试时,应用尝试从proto store获取List时抛出对应错误。

相关配置

build.gradle(:app) 配置

androidTestImplementation(libs.androidx.datastore.core)
androidTestImplementation(libs.androidx.datastore.preferences)
androidTestImplementation(libs.androidx.datastore.preferences.core)
androidTestImplementation(project(":common"))
testImplementation(project(":common"))
androidTestImplementation(libs.protobuf.javalite)
testImplementation(libs.protobuf.javalite)

版本统一配置

为确保protobuf-javalite版本一致,添加了如下配置:

allprojects {
    configurations.all {
        resolutionStrategy.eachDependency {
            if (requested.group == "com.google.protobuf" && requested.name == "protobuf-javalite") {
                useVersion("3.25.1")
                because("Older versions lack registerDefaultInstance()")
            }
        }
    }
}

核心代码实现

StringListSerializer 定义

private class StringListSerializer : Serializer<List<String>> {
    override val defaultValue: List<String>
        get() = emptyList()

    override suspend fun readFrom(input: InputStream): List<String> {
        try {
            val longList = ListOfString.parseFrom(input)
            return longList.itemList
        } catch (exception: Exception) {
            throw CorruptionException("Cannot read proto.", exception)
        }
    }

    override suspend fun writeTo(t: List<String>, output: OutputStream) {
        val longList = ListOfString.newBuilder()
            .addAllItem(t)
            .build()
        longList.writeTo(output)
    }
}

StringListDataStoreProperty 实现

class StringListDataStoreProperty(
    private val context: Context,
    private val dataStoreName: String,
    private val coroutineScope: CoroutineScope
) : ReadWriteProperty<Any, List<String>?> {

    private val Context.listOfLongDataStore: DataStore<List<String>> by dataStore(
        fileName = dataStoreName,
        serializer = StringListSerializer(),
    )

    override fun getValue(thisRef: Any, property: KProperty<*>): List<String> = runBlocking {
        return@runBlocking context.listOfLongDataStore.data.first()
    }

    override fun setValue(thisRef: Any, property: KProperty<*>, value: List<String>?) {
        coroutineScope.launch {
            context.listOfLongDataStore.updateData {
                value!!
            }
        }
    }
}

MyDataStoreManager 实现

class MyDataStoreManager @Inject constructor(
    @ApplicationContext val context: Context,
    @ApplicationScope val coroutineScope: CoroutineScope,
    private val dataStore: DataStore<Preferences>
) : MyDataStore {
    
    //...

    override var myListOfStrings: List<String>? by StringListDataStoreProperty(
        context = context,
        dataStoreName = "protoStoreName",
        coroutineScope = coroutineScope
    )

    //...
}

请问我遗漏了什么配置或者哪里操作有误?

内容的提问来源于stack exchange,提问作者ViksaaSkool

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 09:06:11