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

父类BaseActivity中SensorManager实现的内存泄漏问题排查与优化

问题描述

我已使用SensorManager处理屏幕方向,功能运行正常

但在BaseActivity中如下设置时出现了内存泄漏:

abstract class BaseActivity : AppCompatActivity(), SensorOrientationChangeNotifier.Listener  {
   override fun onResume() {
        super.onResume()
        SensorOrientationChangeNotifier.getInstance(this)?.addListener(this)
    }

    override fun onPause() {
        super.onPause()
        SensorOrientationChangeNotifier.getInstance(this)?.remove(this)
    }
}

SensorOrientationChangeNotifier.kt 代码

class SensorOrientationChangeNotifier private constructor(applicationContext: Context) {

    private val mListeners = ArrayList<WeakReference<Listener?>>(3)
    var orientation = 0
        private set
    private val mSensorEventListener: SensorEventListener
    private val mSensorManager: SensorManager

    init {
        mSensorEventListener = NotifierSensorEventListener()
        mSensorManager =
            applicationContext.getSystemService(Context.SENSOR_SERVICE) as SensorManager
    }

    /**
     * Call on activity reset()
     */
    private fun onResume() {
        mSensorManager.registerListener(
            mSensorEventListener,
            mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
            SensorManager.SENSOR_DELAY_NORMAL
        )
    }

    /**
     * Call on activity onPause()
     */
    private fun onPause() {
        mSensorManager.unregisterListener(mSensorEventListener)
    }

    private inner class NotifierSensorEventListener : SensorEventListener {
        override fun onSensorChanged(event: SensorEvent) {
            val x = event.values[0]
            val y = event.values[1]
            var newOrientation: Int = orientation
            if (x < 5 && x > -5 && y > 5) newOrientation =
                0 else if (x < -5 && y < 5 && y > -5) newOrientation =
                90 else if (x < 5 && x > -5 && y < -5) newOrientation =
                180 else if (x > 5 && y < 5 && y > -5) newOrientation = 270


            ///Timber.v("Matas_mOrientation = "+ newOrientation+"   ["+event.values[0]+","+event.values[1]+","+event.values[2]+"]");
            if (orientation != newOrientation) {
                Timber.v("Matas_mOrientation-Orientation-> NEW")
                orientation = newOrientation
                notifyListeners()
            } else {
                ///Timber.v("Matas_mOrientation-Orientation-> OLD");
            }
        }

        override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}
    }

    interface Listener {
        fun onOrientationChange(orientation: Int)
    }

    fun addListener(listener: Listener) {
        if (get(listener) == null) // prevent duplications
            mListeners.add(WeakReference(listener))
        if (mListeners.size == 1) {
            onResume() // this is the first client
        }
    }

    fun remove(listener: Listener) {
        val listenerWR = get(listener)
        remove(listenerWR)
    }

    private fun remove(listenerWR: WeakReference<Listener?>?) {
        if (listenerWR != null) mListeners.remove(listenerWR)
        if (mListeners.size == 0) {
            onPause()
        }
    }

    private operator fun get(listener: Listener): WeakReference<Listener?>? {
        for (existingListener in mListeners) if (existingListener.get() === listener) return existingListener
        return null
    }

    private fun notifyListeners() {
        val deadLiksArr = ArrayList<WeakReference<Listener?>>()
        for (wr in mListeners) {
            if (wr.get() == null) deadLiksArr.add(wr) else wr.get()!!
                .onOrientationChange(orientation)
        }

        // remove dead references
        for (wr in deadLiksArr) {
            mListeners.remove(wr)
        }
    }

    val isPortrait: Boolean = orientation == 0 || orientation == 180
    val isLandscape: Boolean = !isPortrait

    companion object {
        val TAG = javaClass.simpleName
        private var mInstance: SensorOrientationChangeNotifier? = null
        fun getInstance(applicationContext: Context): SensorOrientationChangeNotifier? {
            if (mInstance == null) mInstance = SensorOrientationChangeNotifier(applicationContext)
            return mInstance
        }
    }
}

我认为切换Activity时出现了context泄漏,问题根源在于单例对象mInstance始终不为空。

有没有更好的实现方案能在BaseActivity中避免内存泄漏?

我考虑过直接传入带applicationContext的SensorManager:

val sensorManager = applicationContext.getSystemService(Context.SENSOR_SERVICE) as SensorManager
SensorOrientationChangeNotifier.getInstance(sensorManager)?.addListener(this)

内容的提问来源于stack exchange,提问作者Taimoor Khan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 01:51:13