Android Studio集成OpenAI API遇Ktor ContentNegotiation类找不到崩溃问题
集成OpenAI API时Android应用启动崩溃(找不到ContentNegotiation类)
问题背景
正在开发一款文本RPG Android应用,使用Kotlin语言。UI完成后开始集成OpenAI API,编写了API请求代码,IDE中无语法错误,但应用启动时立即崩溃。
崩溃日志
启动时Logcat输出如下错误:
java.lang.NoClassDefFoundError: Failed resolution of: Lio/ktor/client/plugins/contentnegotiation/ContentNegotiation; ... Caused by: java.lang.ClassNotFoundException: Didn't find class "io.ktor.client.plugins.contentnegotiation.ContentNegotiation" on path: DexPathList[[zip file "/data/app/~~PDlu8hz4gyE6dIA4WjsxSA==/com.example.worldcrafter-jSXV8Rrpgh6Ga_DxfOZ7qg==/base.apk"],nativeLibraryDirectories=[/data/app/~~PDlu8hz4gyE6dIA4WjsxSA==/com.example.worldcrafter-jSXV8Rrpgh6Ga_DxfOZ7qg==/lib/x86_64, /data/app/~~PDlu8hz4gyE6dIA4WjsxSA==/com.example.worldcrafter-jSXV8Rrpgh6Ga_DxfOZ7qg==/base.apk!/lib/x86_64, /system/lib64, /system_ext/lib64]]
应用启动前还有两条警告:
com.example.worldcrafter W Unable to open '/data/app/~~PDlu8hz4gyE6dIA4WjsxSA==/com.example.worldcrafter-jSXV8Rrpgh6Ga_DxfOZ7qg==/base.dm': No such file or directory 2024-12-12 11:50:03.402 20454-20454 ziparchive com.example.worldcrafter W Unable to open '/data/app/~~PDlu8hz4gyE6dIA4WjsxSA==/com.example.worldcrafter-jSXV8Rrpgh6Ga_DxfOZ7qg==/base.dm': No such file or directory
API请求代码
编写的OpenAI API请求函数如下:
@OptIn(DelicateCoroutinesApi::class) fun makeAPIRequest(message: String) { // Launch a coroutine to handle the API request asynchronously GlobalScope.launch(Dispatchers.IO) { // Create a ChatCompletionRequest to send to OpenAI val chatRequest = ChatCompletionRequest( model = ModelId("gpt-3.5-turbo-1106"), // Use the correct model name messages = mutableListOf( ChatMessage( role = Role.User, // User sends the message content = message // The message entered by the user ) ), temperature = 0.7, maxTokens = 150 ) // Send the request to OpenAI API and get the response asynchronously val response = openAI.chatCompletion(chatRequest) // Process the response on the main thread withContext(Dispatchers.Main) { val responseMessage = response.choices.first().message // Handle the response here, e.g., update UI or process data chatGPTResponse = responseMessage.toString() } } }
注:未将该函数设为async是因为要在MainActivity.kt的其他地方调用。
依赖配置
当前项目的依赖配置如下:
dependencies { implementation(libs.androidx.core.ktx) implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.activity.compose) implementation(platform(libs.androidx.compose.bom)) implementation(libs.androidx.ui) implementation(libs.androidx.ui.graphics) implementation(libs.androidx.ui.tooling.preview) implementation(libs.androidx.material3) implementation(libs.androidx.constraintlayout) implementation(libs.androidx.recyclerview) implementation(libs.material) testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) androidTestImplementation(platform(libs.androidx.compose.bom)) androidTestImplementation(libs.androidx.ui.test.junit4) debugImplementation(libs.androidx.ui.tooling) debugImplementation(libs.androidx.ui.test.manifest) implementation("com.aallam.openai:openai-client:3.8.2") implementation(platform(libs.ktor.bom)) //not using the toml file because i hate it with a burning passion implementation("io.ktor:ktor-client-core:3.0.2") implementation("io.ktor:ktor-client-android:3.0.2") implementation("io.ktor:ktor-client-content-negotiation:3.0.2") implementation("io.ktor:ktor-serialization-kotlinx-json:3.0.2") implementation("io.ktor:ktor-client-logging:3.0.2") implementation("io.ktor:ktor-client-cio:3.0.2") }
MainActivity精简代码
package com.example.worldcrafter import android.os.Bundle import android.view.KeyEvent import android.view.inputmethod.EditorInfo import android.view.inputmethod.InputMethodManager import android.widget.Button import android.widget.TextView import androidx.activity.ComponentActivity import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.aallam.openai.api.chat.* import com.aallam.openai.api.model.ModelId import com.aallam.openai.api.core.Role import com.aallam.openai.api.http.Timeout import com.aallam.openai.client.OpenAI import com.aallam.openai.client.OpenAIConfig import com.example.worldcrafter.ui.adapters.ChatAdapter import com.google.android.material.textfield.TextInputEditText import kotlinx.coroutines.DelicateCoroutinesApi import kotlin.time.Duration.Companion.seconds import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext // App startup class MainActivity() : ComponentActivity() { val openAI = OpenAI(OpenAIConfig(BuildConfig.OPENAI_API_KEY, timeout = Timeout(socket = 60.seconds))) var chatGPTResponse: String = "" // on creation of app override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 省略其他初始化代码,调用initChatButtons() } // Initialize the buttons in the Chat layout private fun initChatButtons() { // Setup navigation buttons setupButton(R.id.btSavedChats2) { switchLayout(LayoutType.SAVED_CHATS) } setupButton(R.id.btSettings2) { switchLayout(LayoutType.SETTINGS) } // Initialize mutable list to store messages val messages = mutableListOf<String>() // Set up RecyclerView and Adapter val recyclerView = findViewById<RecyclerView>(R.id.recyclerView) val chatAdapter = ChatAdapter(messages) // Use ChatAdapter directly recyclerView.layoutManager = LinearLayoutManager(this) recyclerView.adapter = chatAdapter // Reference to TextInputEditText val inputEditText = findViewById<TextInputEditText>(R.id.textInputEditText) // Set an action listener to detect "Enter" key inputEditText.setOnEditorActionListener { _, actionId, event -> if (actionId == EditorInfo.IME_ACTION_DONE || (event != null && event.keyCode == KeyEvent.KEYCODE_ENTER)) { val message = inputEditText.text.toString().trim() if (message.isNotEmpty()) { // Use addMessage() instead of direct list manipulation chatAdapter.addMessage(message) // Scroll to the latest message recyclerView.smoothScrollToPosition(messages.size - 1) //chatgpt message here makeAPIRequest(message) // Add the response to the list chatAdapter.addMessage(chatGPTResponse) recyclerView.smoothScrollToPosition(messages.size - 1) // Clear the input field inputEditText.text?.clear() // Hide the keyboard after the message is added hideKeyboard() return@setOnEditorActionListener true } } false } } //chatgpt stuff @OptIn(DelicateCoroutinesApi::class) fun makeAPIRequest(message: String) { // Launch a coroutine to handle the API request asynchronously GlobalScope.launch(Dispatchers.IO) { // Create a ChatCompletionRequest to send to OpenAI val chatRequest = ChatCompletionRequest( model = ModelId("gpt-3.5-turbo-1106"), // Use the correct model name messages = mutableListOf( ChatMessage( role = Role.User, // User sends the message content = message // The message entered by the user ) ), temperature = 0.7, maxTokens = 150 ) // Send the request to OpenAI API and get the response asynchronously val response = openAI.chatCompletion(chatRequest) // Process the response on the main thread withContext(Dispatchers.Main) { val responseMessage = response.choices.first().message // Handle the response here, e.g., update UI or process data chatGPTResponse = responseMessage.toString() } } } }
已尝试的解决方法
- 清理并重建项目
- 更换Content Negotiation、Kotlin及Ktor的版本
以上方法均未解决问题,寻求帮助。
内容的提问来源于stack exchange,提问作者Alexander Mailyants
相关产品推荐
相关产品推荐

