【问题标题】:Sms BroadCastReceiver Leaks Memory短信广播接收器泄漏内存
【发布时间】: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


【解决方案1】:

这里泄露了伴随对象中的mListener 字段(所以它是静态的)。泄漏静电是常见的情况,所以最好不要使用它们。如果可以的话,你应该改变你的应用架构。

但是您可以创建另一个静态方法来清除 mListener 值并在活动停止后调用它。它更快更容易。

【讨论】:

    猜你喜欢
    • 2022-01-08
    • 2011-05-06
    • 1970-01-01
    • 2018-09-17
    • 2012-11-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多