【发布时间】:2019-03-16 02:33:06
【问题描述】:
我有一个使用手机的注册屏幕,当用户使用手机号码注册时,会发送一个 otp,我会收听该 otp,这样用户就不必手动输入 otp 但是当听那个 otp 时,我得到了内存泄漏。
这是我收听短信的代码
class SmsReceiver : BroadcastReceiver() {
private var bundle: Bundle? = null
private lateinit var currentSMS: SmsMessage
private var otp: String? = null
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action.equals("android.provider.Telephony.SMS_RECEIVED")) {
bundle = intent?.extras
if (bundle != null) {
val pduObjects = bundle?.get("pdus") as Array<*>
for (i in pduObjects) {
currentSMS = i?.let { getIncomingMessage(it, bundle!!) }!!
val sender = currentSMS.displayOriginatingAddress
if (sender.endsWith("VK-DICEAP") || sender.endsWith("VM-DICEAP") || sender.endsWith("ID-DICEAP")) {
val msgBody = currentSMS.messageBody
otp = msgBody.replace(("[a-zA-Z.]").toRegex(), "").trim()
mListener.messageReceived(otp ?: "")
}
}
}
}
}
companion object {
private lateinit var mListener: SmsListener
fun bindListener(listener: SmsListener) {
mListener = listener
}
}
private fun getIncomingMessage(aObject: Any, bundle: Bundle): SmsMessage {
val currentSMS: SmsMessage
currentSMS = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val format = bundle.getString("format")
SmsMessage.createFromPdu(aObject as ByteArray?, format)
} else {
SmsMessage.createFromPdu(aObject as ByteArray?)
}
return currentSMS
}
}
现在在我的活动中,我使用如下代码
在创建时检查用户是否已授予权限
private fun checkSmsPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(Manifest.permission.RECEIVE_SMS) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(arrayOf(Manifest.permission.RECEIVE_SMS), RECEIVE_SMS)
} else {
receiveSms()
}
} else {
receiveSms()
}
}
如果是,那么我只需将 otp 发送到我的服务器
private fun receiveSms() {
SmsReceiver.bindListener(object : SmsListener {
override fun messageReceived(messageText: String) {
//send otp to server
}
})
}
我为回调创建了一个单独的接口
interface SmsListener {
fun messageReceived(messageText: String)
}
现在我在 stackoverflow 上搜索了这个,我发现你应该通过代码注册和注销,而不是在 Manifest 文件中注册接收器 所以我尝试使用如下代码
override fun onStart() {
super.onStart()
smsReceiver = SmsReceiver()
val filter = IntentFilter()
filter.addAction("android.provider.Telephony.SMS_RECEIVED")
registerReceiver(smsReceiver, filter)
checkSmsPermission()
}
override fun onStop() {
super.onStop()
unregisterReceiver(smsReceiver)
}
但我的应用程序中仍然存在泄漏内存。我正在使用 LeakCanary 来检测我的应用程序中的泄漏。
这是泄露的截图
【问题讨论】:
-
使您的
smsReceiver可以为空,并在注销后将其设置为空。 -
@Ircover 会尝试让您知道
-
@Ircover 我仍然遇到内存泄漏。我已经注释了 Manifest 中的代码,并在 onStop 中取消注册后使 smsReceiver 可以为空
-
哦,你的静态
mListener泄露了。抱歉,没看到。)您可以在bindListener附近创建清洁方法并在活动停止时调用它,但我建议您更改架构以不使用静态。 -
@Ircover 成功了。请发表您的评论作为答案,我会接受它
标签: android memory-leaks kotlin broadcastreceiver leakcanary