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

Kotlin开发SMS聊天应用:求助Activity状态保存方法

问题描述

我是Android与Kotlin新手,开发了一款基于SMS的聊天应用,使用RecyclerView和GroupieViewHolder展示聊天内容,希望实现重启应用后保存所有聊天状态。此前找到的相关方案均为Java版本,现寻求最简单的Kotlin实现方式,附上应用聊天界面截图及smsActivity.kt代码:

class smsActivity : AppCompatActivity() {

    private val messageAdapter = GroupAdapter<GroupieViewHolder>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_sms)

        val recyclerView = findViewById<RecyclerView>(R.id.listmessage)
        val button = findViewById<Button>(R.id.button)
        val editmessage = findViewById<EditText>(R.id.editText)
        val sharedPeref = getSharedPreferences("setNumber", MODE_PRIVATE)
        val number = sharedPeref.getString("number", null)

        recyclerView.adapter = messageAdapter
        populateData()

        receiveAutoResponse()
        button.setOnClickListener {
            val message = Message(text = editmessage.text.toString(), sendBy = "me")
            val smssend = editmessage.text.toString()
            val sendMessageItem = SendMessageItem(message)

            messageAdapter.add(sendMessageItem)
            editmessage.text.clear()
            receiveAutoResponse()
            recyclerView.scrollToPosition(messageAdapter.getItemCount() - 1);

            try {
                val smsManager: SmsManager = SmsManager.getDefault()

                smsManager.sendTextMessage(number, null, smssend, null, null)
                Toast.makeText(
                    applicationContext,
                    "بخاری 3 =دریافت گزارش ✅ دریافت گزارش چندین ثانیه زمان می برد ، لطفا برای ارسال دستور بعدی کمی صبر کنید",
                    Toast.LENGTH_LONG
                ).show()

            } catch (e: Exception) {
                Toast.makeText(
                    applicationContext,
                    "لطفا  ابتدا شماره سیستم را وارد کنید !",
                    Toast.LENGTH_SHORT
                ).show()
                val intent = Intent(this, setnumberActivity::class.java)
                this.startActivity(intent)
            }
        }
    }

    fun ScrollView.scrollToBottom() {
        val lastChild = getChildAt(childCount - 1)
        val bottom = lastChild.bottom + paddingBottom
        val delta = bottom - (scrollY + height)
        smoothScrollBy(0, delta)
    }

    private fun populateData() {
        val data = listOf<Message>()
        data.forEach {
            if (it.sendBy == "me") {
                messageAdapter.add(SendMessageItem(it))
            } else {
                messageAdapter.add(ReceiveMessageItem(it))
            }
        }
    }

    private fun receiveAutoResponse() {
        GlobalScope.launch(Dispatchers.Main) {
            delay(1000)
            val sharedPeref = getSharedPreferences("setNumber", MODE_PRIVATE)
            val nums = "+98" + sharedPeref.getString("number", null)
            val cursor: Cursor? = getContentResolver().query(
                Uri.parse("content://sms"),
                null,
                "address='$nums'",
                null,
                null
            )
            cursor?.moveToFirst()
            val messageSend = cursor?.getString(12)
            val receive = Message(text = "$messageSend", sendBy = "me")
            val receiveItem = ReceiveMessageItem(receive)
            messageAdapter.add(receiveItem)
            val recyclerView = findViewById<RecyclerView>(R.id.listmessage)
            recyclerView.scrollToPosition(messageAdapter.getItemCount() - 1);
        }
    }

}

class SendMessageItem(private val message: Message) : BindableItem<ItemMessageSendBinding>() {

    override fun getLayout(): Int {
        return R.layout.item_message_send
    }

    override fun bind(viewBinding: ItemMessageSendBinding, position: Int) {
        viewBinding.message = message
    }
}

class ReceiveMessageItem(private val message: Message) : BindableItem<ItemMessageReceiveBinding>() {
    override fun getLayout(): Int {
        return R.layout.item_message_receive

    }

    override fun bind(viewBinding: ItemMessageReceiveBinding, position: Int) {
        viewBinding.message = message
    }
}
最简单的Kotlin实现方案

采用SharedPreferences+Gson序列化的方案,轻量且易上手:

步骤1:添加Gson依赖

在模块级build.gradle的dependencies块中添加:

implementation 'com.google.code.gson:gson:2.10.1'

步骤2:封装消息存储工具类

创建单例类统一处理消息的保存与读取:

import android.content.Context
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken

object MessageStorage {
    private const val PREF_NAME = "ChatMessages"
    private const val KEY_MESSAGES = "messages_list"
    private val gson = Gson()

    // 保存消息列表到SharedPreferences
    fun saveMessages(context: Context, messages: List<Message>) {
        val prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
        val json = gson.toJson(messages)
        prefs.edit().putString(KEY_MESSAGES, json).apply()
    }

    // 从SharedPreferences读取消息列表
    fun loadMessages(context: Context): List<Message> {
        val prefs = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
        val json = prefs.getString(KEY_MESSAGES, null) ?: return emptyList()
        val type = object : TypeToken<List<Message>>() {}.type
        return gson.fromJson(json, type)
    }
}

步骤3:修改smsActivity集成存储逻辑

  1. 修改populateData方法,加载保存的消息
private fun populateData() {
    val savedMessages = MessageStorage.loadMessages(this)
    savedMessages.forEach {
        if (it.sendBy == "me") {
            messageAdapter.add(SendMessageItem(it))
        } else {
            messageAdapter.add(ReceiveMessageItem(it))
        }
    }
}
  1. 发送消息时保存聊天状态
    在发送按钮的点击事件中,添加保存逻辑:
button.setOnClickListener {
    val message = Message(text = editmessage.text.toString(), sendBy = "me")
    val smssend = editmessage.text.toString()
    val sendMessageItem = SendMessageItem(message)

    messageAdapter.add(sendMessageItem)
    editmessage.text.clear()
    recyclerView.scrollToPosition(messageAdapter.getItemCount() - 1);

    // 保存当前所有消息
    val currentMessages = messageAdapter.items.map {
        when(it) {
            is SendMessageItem -> it.message
            is ReceiveMessageItem -> it.message
            else -> throw IllegalArgumentException("未知消息类型")
        }
    }
    MessageStorage.saveMessages(this, currentMessages)

    // 原有SMS发送逻辑不变
    try {
        val smsManager: SmsManager = SmsManager.getDefault()
        smsManager.sendTextMessage(number, null, smssend, null, null)
        Toast.makeText(
            applicationContext,
            "بخاری 3 =دریافت گزارش ✅ دریافت گزارش چندین ثانیه زمان می برد ، لطفا برای ارسال دستور بعدی کمی صبر کنید",
            Toast.LENGTH_LONG
        ).show()
    } catch (e: Exception) {
        Toast.makeText(
            applicationContext,
            "لطفا  ابتدا شماره سیستم را وارد کنید !",
            Toast.LENGTH_SHORT
        ).show()
        val intent = Intent(this, setnumberActivity::class.java)
        this.startActivity(intent)
    }
}
  1. 接收消息时保存聊天状态
    在receiveAutoResponse方法末尾添加保存逻辑,同时修正原代码中sendBy的错误(对方消息应标记为"other"而非"me"):
private fun receiveAutoResponse() {
    GlobalScope.launch(Dispatchers.Main) {
        delay(1000)
        val sharedPeref = getSharedPreferences("setNumber", MODE_PRIVATE)
        val nums = "+98" + sharedPeref.getString("number", null)
        val cursor: Cursor? = getContentResolver().query(
            Uri.parse("content://sms"),
            null,
            "address='$nums'",
            null,
            null
        )
        cursor?.moveToFirst()
        val messageSend = cursor?.getString(12)
        // 修正sendBy字段,区分对方消息
        val receive = Message(text = "$messageSend", sendBy = "other")
        val receiveItem = ReceiveMessageItem(receive)
        messageAdapter.add(receiveItem)
        val recyclerView = findViewById<RecyclerView>(R.id.listmessage)
        recyclerView.scrollToPosition(messageAdapter.getItemCount() - 1);

        // 保存当前所有消息
        val currentMessages = messageAdapter.items.map {
            when(it) {
                is SendMessageItem -> it.message
                is ReceiveMessageItem -> it.message
                else -> throw IllegalArgumentException("未知消息类型")
            }
        }
        MessageStorage.saveMessages(this@smsActivity, currentMessages)
    }
}

额外优化建议

  • 确保Message是数据类(默认支持序列化):
data class Message(val text: String, val sendBy: String)
  • 替换GlobalScope为lifecycleScope(更安全的生命周期绑定),需添加依赖:
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.2"

替换后代码改为:lifecycleScope.launch(Dispatchers.Main) { ... }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 02:56:52