Android Studio中Kotlin可变字符串列表存储类加载为空问题
Android聊天存储加载异常问题排查
问题描述
开发Android应用时,自定义ChatStorage单例类存储四类聊天数据:聊天名称(String)、完整聊天内容(MutableList
相关代码与日志
ChatStorage单例类
package com.example.worldcrafter.ui import com.aallam.openai.api.chat.ChatMessage object ChatStorage { private val names = mutableListOf<String>() private val textStorage = mutableListOf<MutableList<String>>() private val summarizedStorage = mutableListOf<MutableList<ChatMessage>>() private val summarizedAmount = mutableListOf<Int>() fun addName(name: String, id: Int? = null) { println("WRLD - Adding name: $name") if (id != null) { names[id] = name } else { names.add(name) } } fun addText(text: MutableList<String>, id: Int? = null) { println("WRLD - Adding text: $text") if (id != null) { textStorage[id] = text } else { textStorage.add(text) } } fun addSummarized(summarized: MutableList<ChatMessage>, id: Int? = null) { println("WRLD - Adding summarized: $summarized") if (id != null) { summarizedStorage[id] = summarized } else { summarizedStorage.add(summarized) } } fun addSummarizedAmount(amount: Int, id: Int? = null) { println("WRLD - Adding summarized amount: $amount") if (id != null) { summarizedAmount[id] = amount } else { summarizedAmount.add(amount) } } fun makeSave(name: String, text: MutableList<String>, summarized: MutableList<ChatMessage>, summarizedAmt: Int, id: Int? = null) { if (id != null) { addName(name, id) addText(text, id) addSummarized(summarized, id) addSummarizedAmount(summarizedAmt, id) } else { addName(name) addText(text) addSummarized(summarized) addSummarizedAmount(summarizedAmt) } println("WRLD - Save Complete.") } fun getIDByName(str: String): Int? { println("WRLD - Getting ID by name: $str") for (i in 0 until names.size) { if (names[i] == str) { return i } } return null } fun getName(index: Int): String { println("WRLD - Getting name at index: $index. Name: ${names[index]}") return names[index] } fun getText(index: Int): MutableList<String> { println("WRLD - Getting text at index: $index. Text: ${textStorage[index]}") return textStorage[index] } fun getSummarized(index: Int): MutableList<ChatMessage> { println("WRLD - Getting summarized at index: $index. Summarized: ${summarizedStorage[index]}") return summarizedStorage[index] } fun getSummarizedAmount(index: Int): Int { println("WRLD - Getting summarized amount at index: $index. Summarized amount: ${summarizedAmount[index]}") return summarizedAmount[index] } fun getSize(): Int { println("WRLD - Chat storage size: ${names.size}") return names.size } fun deleteSave(index: Int) { println("WRLD - Deleting save at index: $index") names.removeAt(index) textStorage.removeAt(index) summarizedStorage.removeAt(index) summarizedAmount.removeAt(index) } fun clear() { println("WRLD - Clearing chat storage") names.clear() textStorage.clear() summarizedStorage.clear() summarizedAmount.clear() } }
MainActivity.kt相关代码
private fun initSavedChatsMenu() { setupButton(R.id.btAdventure1) { switchLayout(LayoutType.CHAT) } setupButton(R.id.btSettings1) { switchLayout(LayoutType.SETTINGS) } val recyclerView = findViewById<RecyclerView>(R.id.recyclerViewOfSavedChats) val buttonLabels = mutableListOf<String>() // Populate button labels from ChatStorage for (i in 0 until ChatStorage.getSize()) { buttonLabels.add(ChatStorage.getName(i)) } // Initialize the adapter with the labels and a callback val buttonAdapter = ButtonAdapter(buttonLabels) { label -> // Handle button clicks here // For example, switch to the chat layout switchLayout(LayoutType.CHAT) initChatMenu(true, label) } // Set up RecyclerView with the adapter and layout manager recyclerView.adapter = buttonAdapter recyclerView.layoutManager = LinearLayoutManager(this) } // Initialize the buttons in the Chat layout (ChatGPT[3]) private fun initChatMenu(load: Boolean = false, name: String = "") { setupButton(R.id.btSavedChats2) { switchLayout(LayoutType.SAVED_CHATS) } setupButton(R.id.btSettings2) { switchLayout(LayoutType.SETTINGS) } conversation.clear() summarized.clear() // Set up RecyclerView and Adapter val recyclerView = findViewById<RecyclerView>(R.id.recyclerView) val chatAdapter = ChatAdapter(conversation) // Use ChatAdapter directly recyclerView.layoutManager = LinearLayoutManager(this) recyclerView.adapter = chatAdapter // Reference to TextInputEditText val inputEditText = findViewById<TextInputEditText>(R.id.textInputEditText) if (!load) { // 无关代码:处理新聊天初始化 } else { // **Load saved conversation** val chatIndex = ChatStorage.getIDByName(name) ?: return conversation.clear() val tempConversation = ChatStorage.getText(chatIndex) summarized = ChatStorage.getSummarized(chatIndex) summarizedAmt = ChatStorage.getSummarizedAmount(chatIndex) // Notify adapter after adding all messages for (i in 0 until conversation.size) { conversation.add(tempConversation[i]) chatAdapter.notifyItemInserted(i) recyclerView.smoothScrollToPosition(conversation.size - 1) } } // 无关代码:处理新聊天输入 }
日志输出
WRLD - Adding name: istfg if this doesn't workWRLD - Adding text: [Greetings, adventurer! ...] WRLD - Adding summarized: [ChatMessage(role=Role(role=system), messageContent=TextContent(content=Commit this message to memory. ...] WRLD - Adding summarized amount: 0 WRLD - Save Complete. // 以上日志为聊天保存时输出 WRLD - Chat storage size: 1 WRLD - Getting name at index: 0. Name: istfg if this doesn't work // 以上日志为加载保存聊天菜单时输出 WRLD - Getting ID by name: istfg if this doesn't work WRLD - Getting text at index: 0. Text: [] WRLD - Getting summarized at index: 0. Summarized: [ChatMessage(role=Role(role=user), messageContent=TextContent(content=Commit this message to memory. ...] WRLD - Getting summarized amount at index: 0. Summarized amount: 0 // 以上日志为加载聊天时输出
问题原因
- 存储列表引用而非副本:
ChatStorage中直接存储了传入的MutableList引用,而非创建独立副本。如果外部对原列表执行clear()等修改操作,存储在textStorage中的列表也会被同步清空。比如保存聊天后,原conversation列表被clear(),导致存储的聊天内容也为空。 - 加载代码循环条件错误:加载聊天时,循环使用
conversation.size作为遍历上限,但此时conversation刚被clear(),大小为0,循环根本不会执行,因此conversation始终为空。
修复方案
1. 存储列表副本,隔离外部修改
修改ChatStorage的addText和addSummarized方法,存储传入列表的独立副本,避免外部修改影响存储数据:
fun addText(text: MutableList<String>, id: Int? = null) { println("WRLD - Adding text: $text") val textCopy = text.toMutableList() // 创建列表副本 if (id != null) { textStorage[id] = textCopy } else { textStorage.add(textCopy) } } fun addSummarized(summarized: MutableList<ChatMessage>, id: Int? = null) { println("WRLD - Adding summarized: $summarized") val summarizedCopy = summarized.toMutableList() // 创建列表副本 if (id != null) { summarizedStorage[id] = summarizedCopy } else { summarizedStorage.add(summarizedCopy) } }
2. 修正加载代码的循环逻辑
在initChatMenu的加载分支中,修改循环逻辑,遍历目标列表tempConversation的内容,或直接使用addAll简化代码:
// **Load saved conversation** val chatIndex = ChatStorage.getIDByName(name) ?: return conversation.clear() val tempConversation = ChatStorage.getText(chatIndex) summarized = ChatStorage.getSummarized(chatIndex) summarizedAmt = ChatStorage.getSummarizedAmount(chatIndex) // 直接添加所有内容并通知适配器更新 conversation.addAll(tempConversation) chatAdapter.notifyDataSetChanged() recyclerView.smoothScrollToPosition(conversation.size - 1)
如果需要逐个添加并通知列表更新:
for (msg in tempConversation) { conversation.add(msg) chatAdapter.notifyItemInserted(conversation.size - 1) } recyclerView.smoothScrollToPosition(conversation.size - 1)
内容的提问来源于stack exchange,提问作者Alexander Mailyants
相关产品推荐
相关产品推荐

