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集成存储逻辑
- 修改
populateData方法,加载保存的消息
private fun populateData() { val savedMessages = MessageStorage.loadMessages(this) savedMessages.forEach { if (it.sendBy == "me") { messageAdapter.add(SendMessageItem(it)) } else { messageAdapter.add(ReceiveMessageItem(it)) } } }
- 发送消息时保存聊天状态
在发送按钮的点击事件中,添加保存逻辑:
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) } }
- 接收消息时保存聊天状态
在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
相关产品推荐
相关产品推荐

