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

Android Studio中Kotlin可变字符串列表存储类加载为空问题

Android聊天存储加载异常问题排查

问题描述

开发Android应用时,自定义ChatStorage单例类存储四类聊天数据:聊天名称(String)、完整聊天内容(MutableList)、摘要聊天(MutableList)、摘要数量(Int)。目前其他数据加载正常,但完整聊天内容加载时为空——保存时日志显示列表包含内容,加载时日志却显示为空。

相关代码与日志

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
// 以上日志为加载聊天时输出

问题原因

  1. 存储列表引用而非副本:ChatStorage中直接存储了传入的MutableList引用,而非创建独立副本。如果外部对原列表执行clear()等修改操作,存储在textStorage中的列表也会被同步清空。比如保存聊天后,原conversation列表被clear(),导致存储的聊天内容也为空。
  2. 加载代码循环条件错误:加载聊天时,循环使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 12:49:53