Kotlin项目Gradle配置Java版本后仍遇NoSuchMethodError问题排查
问题:Android Kotlin项目中DataInputStream.readAllBytes()抛出NoSuchMethodError
问题代码
@RequiresApi(Build.VERSION_CODES.TIRAMISU) fun startStreaming(setImage: (ByteArray) -> Unit) { scope.launch { while (true) { try { // screenStream is an object of DataInputStream class val jpegImageByteArray = screenStream!!.readAllBytes() //---error-here withContext(Dispatchers.Main) { setImage(jpegImageByteArray) } } catch (e: Exception) { e.printStackTrace() } Thread.sleep(1000) } } }
报错信息
FATAL EXCEPTION: DefaultDispatcher-worker-1 Process: com.example.g_stream, PID: 19524 java.lang.NoSuchMethodError: No virtual method readAllBytes()[B in class Ljava/io/DataInputStream; or its super classes (declaration of 'java.io.DataInputStream' appears in /system/framework/core-oj.jar) at com.example.g_stream.viewmodel.StreamViewModel$startStreaming$1.invokeSuspend(StreamViewModel.kt:119) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106) at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42) at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95) at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:749) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664) Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@a113203, Dispatchers.IO]
当前Gradle配置
plugins { id 'com.android.application' id 'org.jetbrains.kotlin.android' id 'androidx.navigation.safeargs.kotlin' } android { compileSdk 33 defaultConfig { applicationId "com.example.g_stream" minSdk 26 targetSdk 33 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_12 //---see-here targetCompatibility JavaVersion.VERSION_12 //---see-here } kotlinOptions { jvmTarget = '11' //---see-here } buildFeatures { viewBinding true dataBinding true } namespace 'com.example.g_stream' } dependencies { implementation 'androidx.core:core-ktx:1.9.0' implementation 'androidx.appcompat:appcompat:1.5.1' implementation 'com.google.android.material:material:1.6.1' // do not update, keep 1.6.1 implementation 'androidx.constraintlayout:constraintlayout:2.1.4' //------------------------------------------------------------------------------------navigation def nav_version = "2.5.3" implementation "androidx.navigation:navigation-fragment-ktx:$nav_version" implementation "androidx.navigation:navigation-ui-ktx:$nav_version" //--------------------------------------------------------------------------------------espresso testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' //---------------------------------------------------------------------------------------barcode implementation 'com.google.mlkit:barcode-scanning:17.0.3' //---------------------------------------------------------------------------------------CameraX def camerax_version = "1.3.0-alpha02" implementation "androidx.camera:camera-camera2:$camerax_version" implementation "androidx.camera:camera-lifecycle:$camerax_version" implementation "androidx.camera:camera-view:$camerax_version" //------------------------------------------------------------------------------------------Gson implementation 'com.google.code.gson:gson:2.10' //--------------------------------------------------------------------------------------joystick implementation 'io.github.controlwear:virtualjoystick:1.10.1' }
原因分析与解决方案
核心原因
这不是编译版本问题,而是Android运行时API兼容问题:
InputStream.readAllBytes()是Java 9引入的方法,但Android系统直到API 33(Android 13,TIRAMISU)才在系统类中实现该方法。- 你的minSdk为26,当APP运行在低于API33的设备上时,系统的
DataInputStream父类InputStream没有这个方法,因此抛出NoSuchMethodError。 - 修改编译的Java版本(sourceCompatibility、jvmTarget)仅影响编译阶段,无法改变运行时系统类的方法存在性。
解决方法
推荐两种兼容方案:
方案1:使用AndroidX Core KTX的兼容方法
你的项目已依赖androidx.core:core-ktx,可直接使用库中提供的兼容扩展方法readBytes(),它在所有Android版本上都能正常工作:
val jpegImageByteArray = screenStream!!.readBytes()
同时可去掉@RequiresApi(Build.VERSION_CODES.TIRAMISU)注解,因为该方法无需API33支持。
方案2:自行实现读取全部字节的逻辑
如果不想依赖Core KTX,可手动实现读取逻辑:
// 扩展方法,兼容所有Android版本 fun InputStream.readAllBytesCompat(): ByteArray { val buffer = ByteArrayOutputStream() val tempBuffer = ByteArray(1024) var bytesRead: Int while (read(tempBuffer).also { bytesRead = it } != -1) { buffer.write(tempBuffer, 0, bytesRead) } return buffer.toByteArray() } // 调用扩展方法 val jpegImageByteArray = screenStream!!.readAllBytesCompat()
方案3:仅在API33+设备使用系统方法(不推荐)
若一定要用系统的readAllBytes(),需在运行时做版本判断,低版本设备使用兼容逻辑:
val jpegImageByteArray = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { screenStream!!.readAllBytes() } else { // 这里用方案2的readAllBytesCompat()或者Core KTX的readBytes() screenStream!!.readBytes() }
内容的提问来源于stack exchange,提问作者Vaishnav Kanhirathingal
相关产品推荐
相关产品推荐

