我想在我的应用程序中实现新的应用程序内更新库,但是我注意到它在重新创建/旋转时会触发我的活动中的内存泄漏。

这是我从LeakCanary获得的唯一详细信息:

android - 如何使用应用程序内更新库防止内存泄漏-LMLPHP

显然,如果我从应用程序内更新库中删除代码,尤其是addOnSuccessListener,那么我什么都没有:

appUpdateManager.appUpdateInfo.addOnSuccessListener { appUpdateInfo ->
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
        && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)){
            updateInfo.value = appUpdateInfo
            updateAvailable.value = true
        }else{
            updateInfo.value = null
            updateAvailable.value = false
        }
    }


根据this post,我首先使用了一些LiveData,但是问题是相同的,因此我使用了完整的类来处理带有LiveData的回调:

我的服务班级:

class AppUpdateService {

    val updateAvailable: MutableLiveData<Boolean> by lazy { MutableLiveData<Boolean>() }
    val updateDownloaded: MutableLiveData<Boolean> by lazy { MutableLiveData<Boolean>() }
    val updateInfo: MutableLiveData<AppUpdateInfo> by lazy { MutableLiveData<AppUpdateInfo>() }

    fun checkForUpdate(appUpdateManager: AppUpdateManager){
        appUpdateManager.appUpdateInfo.addOnSuccessListener { appUpdateInfo ->
            if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
                    && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)){
                updateInfo.value = appUpdateInfo
                updateAvailable.value = true
            }else{
                updateInfo.value = null
                updateAvailable.value = false
            }
        }
    }

    fun checkUpdateOnResume(appUpdateManager: AppUpdateManager){
        appUpdateManager.appUpdateInfo.addOnSuccessListener {
            updateDownloaded.value = (it.installStatus() == InstallStatus.DOWNLOADED)
        }
    }
}


我的活动简化了:

class MainActivity : BaseActivity(), InstallStateUpdatedListener {

    override fun contentViewID(): Int { return R.layout.activity_main }

    private val UPDATE_REQUEST_CODE = 8000

    private lateinit var appUpdateManager : AppUpdateManager

    private val appUpdateService = AppUpdateService()

    override fun onStateUpdate(state: InstallState?) {
        if(state?.installStatus() == InstallStatus.DOWNLOADED){ notifyUser() }
    }

    // Called in the onCreate()
    override fun setupView(){
        appUpdateManager = AppUpdateManagerFactory.create(this)
        appUpdateManager.registerListener(this)
        setupAppUpdateServiceObservers()
        // Check for Update
        appUpdateService.checkForUpdate(appUpdateManager)
    }

    private fun setupAppUpdateServiceObservers(){
        appUpdateService.updateAvailable.observe(this, Observer {
            if (it)
                requestUpdate(appUpdateService.updateInfo.value)
        })

        appUpdateService.updateDownloaded.observe(this, Observer {
            if (it)
                notifyUser()
        })
    }

    private fun requestUpdate(appUpdateInfo: AppUpdateInfo?){
        appUpdateManager.startUpdateFlowForResult(appUpdateInfo, AppUpdateType.FLEXIBLE, this, UPDATE_REQUEST_CODE)
    }

    private fun notifyUser(){
        showSnackbar(getString(R.string.updated_downloaded), getString(R.string.restart)) {
            appUpdateManager.completeUpdate()
            appUpdateManager.unregisterListener(this)
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == UPDATE_REQUEST_CODE) {
            if (resultCode != RESULT_OK) {
                Timber.d("Update flow failed! Result code: $resultCode")
            }
        }
    }

    override fun onDestroy() {
        appUpdateManager.unregisterListener(this)
        super.onDestroy()
    }

    override fun onResume() {
        super.onResume()
        appUpdateService.checkUpdateOnResume(appUpdateManager)
    }

}


我真的不明白如何避免内存泄漏,因为必须使用活动的上下文来创建appUpdateManager,这似乎是导致回调发生内存泄漏的原因。

有人已经实现了它而没有这个问题吗?

最佳答案

使用对上下文的弱引用可能会解决您的内存泄漏问题。在您的活动中写下:

WeakReference<Context> contextWeakReference = new WeakReference<Context>(this);

Context context = contextWeakReference.get();
if (context != null) {
   // Register using context here
}


有很多关于WeakReference,垃圾回收和内存泄漏的好文章,以阅读有关该主题的更多信息。

另外,不能保证onDestroy()会被调用。当您启动另一个Activity时,调用了onPause()和onStop()方法,而不是onDestroy()。

当您单击返回按钮或调用finish()方法时,将调用onDestroy()。因此,请在onPause()或onStop()中注销侦听器。如果您在onDestroy()方法中注销,则可能会导致内存泄漏。

另一个想法是,由于AppUpdateService类不是ViewModel的子类,因此它不是生命周期感知的。我不确定,但是,您可能需要在活动的onstop / onDestroy中删除观察者,并将其添加到onResume中。 (观察者对LifecycleOwner有强烈的参考,这里是活动)要做到这一点,您需要定义观察者以便以后可以删除它们。就像是:

MutableLiveData<Boolean> someData = new MutableLiveData<>;


然后在onResume中:

someData = appUpdateService.updateAvailable;
someData.observe()


并在onStop中:

someData.removeObservers()


只是一个猜测,但是,我希望它会有所帮助。

07-26 09:41
查看更多