인앱 업데이트 라이브러리로 메모리 누수를 방지하는 방법

보롬 보

내 앱에 새로운 인앱 업데이트 라이브러리를 구현하고 싶지만 재생성 / 회전 할 때 내 활동에서 메모리 누수가 발생하는 것을 확인했습니다.

LeakCanary의 유일한 세부 정보는 다음과 같습니다.

LeakCanary 추적

분명히 In-App Update lib, 특히 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
        }
    }

이 게시물 에 따르면 먼저 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가 활동의 컨텍스트로 생성되어야하기 때문에 메모리 누수를 피하는 방법을 정말로 이해하지 못하며, 콜백으로 메모리 누수를 일으키는 원인으로 보입니다.

누군가이 문제없이 이미 구현 했습니까?

보롬 보

@Sina Farahzadi 덕분에 많은 것을 검색하고 시도했으며 문제가 appUpdateManager.appUdateInfoTask 개체를 사용한 호출 이라는 것을 알았습니다 .

메모리 누수를 해결하기 위해 찾은 방법은 활동의 컨텍스트 대신 applicationContext를 사용하는 것입니다. 이것이 최선의 해결책인지는 모르겠지만 지금까지 찾은 해결책입니다. 내 서비스 클래스에서 모두 내보냈으므로 여기에 내 코드가 있습니다.

AppUpdateService.kt :

class AppUpdateService : InstallStateUpdatedListener {

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

    private var appUpdateManager : AppUpdateManager? = null
    private var appUpdateInfoTask: Task<AppUpdateInfo>? = null

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

    fun setupAppUpdateManager(context: Context){
        appUpdateManager = AppUpdateManagerFactory.create(context)
        appUpdateManager?.registerListener(this)
        checkForUpdate()
    }

    fun onStopCalled(){
        appUpdateManager?.unregisterListener(this)
        appUpdateInfoTask = null
        appUpdateManager = null
    }

    fun checkForUpdate(){
        appUpdateInfoTask = appUpdateManager?.appUpdateInfo
        appUpdateInfoTask?.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 startUpdate(activity: Activity, code: Int){
        appUpdateManager?.startUpdateFlowForResult(updateInfo.value, AppUpdateType.FLEXIBLE, activity, code)
    }

    fun updateComplete(){
        appUpdateManager?.completeUpdate()
        appUpdateManager?.unregisterListener(this)
    }

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

}

MainActivity 단순화 :

class MainActivity : BaseActivity(){

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

    private val UPDATE_REQUEST_CODE = 8000

    private var appUpdateService: AppUpdateService? = AppUpdateService()

    /**
     * Setup the view of the activity (navigation and menus)
     */
    override fun setupView(){
        val contextWeakReference = WeakReference<Context>(applicationContext)
        contextWeakReference.get()?.let {weakContext ->
            appUpdateService?.setupAppUpdateManager(weakContext)
        }
    }

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

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

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

    private fun removeAppUpdateServiceObservers(){
        appUpdateService?.updateAvailable?.removeObservers(this)
        appUpdateService?.updateDownloaded?.removeObservers(this)
        appUpdateService?.notifyUser?.removeObservers(this)
    }

    private fun requestUpdate(){
        appUpdateService?.startUpdate(this, UPDATE_REQUEST_CODE)
    }

    private fun notifyUser(){
        showSnackbar(getString(R.string.updated_downloaded), getString(R.string.restart)) {
            appUpdateService?.updateComplete()
        }
    }

    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 onStop() {
        appUpdateService?.onStopCalled()
        removeAppUpdateServiceObservers()
        appUpdateService = null
        super.onStop()
    }

    override fun onResume() {
        super.onResume()
        setupAppUpdateServiceObservers()
        appUpdateService?.checkUpdateOnResume()
    }

}

지금은 그대로 유지하고 다른 방법을 계속 모색하겠습니다. 누군가가 더 나은 방법이 있는지 알려주십시오.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

OpenSSL 라이브러리를 업데이트하는 방법

분류에서Dev

클러스터 인식을 사용하여 jar 데이터를 라이브러리로 유지하는 방법

분류에서Dev

클래스 라이브러리의 메인 앱에서 dryioc 컨테이너를 사용하는 방법

분류에서Dev

Android 라이브러리를 Java 라이브러리로 변경하는 방법

분류에서Dev

EventEmitter 메모리 누수 감지 : CSV 데이터를 여러 모듈로 전달하는 적절한 방법?

분류에서Dev

Google API 자바 스크립트 클라이언트 라이브러리를 Chrome 앱에로드하는 방법

분류에서Dev

모든 서버 인스턴스에서 로컬 메모리 캐시를 업데이트하는 방법

분류에서Dev

바인딩 라이브러리에서 Xamarin iOS 프로젝트에 메서드를 사용하는 방법

분류에서Dev

Ubuntu 16.04 : 최신 라이브러리로 YubiKey 개인화 도구 (GUI)를 업데이트하는 방법은 무엇입니까?

분류에서Dev

jquery 확인 라이브러리로 올바른 링크를 대상으로 지정하는 방법

분류에서Dev

'라이브러리 누락'오류를 방지하는 방법 Linux

분류에서Dev

OpenShift 온라인에서 "다운로드 가능한 카트리지"를 업데이트하는 방법

분류에서Dev

PyKCS11 라이브러리로 서명 된 데이터를 확인하는 방법

분류에서Dev

cppyy에서 라이브러리를로드하는 방법?

분류에서Dev

cppyy에서 라이브러리를로드하는 방법?

분류에서Dev

CMake로 라이브러리를 빌드하는 방법

분류에서Dev

.NetOffice 라이브러리로 헤더를 추가하는 방법

분류에서Dev

paper.js 라이브러리를로드하는 방법?

분류에서Dev

내 프로그램에 메모리 누수가 없는지 확인하는 방법이 있습니까?

분류에서Dev

foreach 라이브러리를로드하지 않고 사용하는 방법

분류에서Dev

웹 사이트에서 라이브러리를 업데이트하는 방법은 무엇입니까?

분류에서Dev

코드에서 메모리 누수를 방지하는 방법

분류에서Dev

iOS에서 ARC 메모리 누수를 방지하는 방법

분류에서Dev

라이브러리 누락으로 인해 믹서에 연결되지 않는 Pulseaudio를 해결하는 방법은 무엇입니까?

분류에서Dev

라이브러리를 정적 / 공유 라이브러리가 아닌 내 앱 소스의 일부로 CMake 컴파일하는 방법은 무엇입니까?

분류에서Dev

Android에서 공유 라이브러리로드를 지연하는 방법

분류에서Dev

Ion 라이브러리를 사용하여 이미지를 다운로드하고 앱 디렉토리에 저장하는 방법

분류에서Dev

Python Pandas 라이브러리로 데이터를 변경하는 방법

분류에서Dev

Windows 개발 : 내 앱의 메모리 누수 여부를 확인하는 방법은 무엇입니까?

Related 관련 기사

  1. 1

    OpenSSL 라이브러리를 업데이트하는 방법

  2. 2

    클러스터 인식을 사용하여 jar 데이터를 라이브러리로 유지하는 방법

  3. 3

    클래스 라이브러리의 메인 앱에서 dryioc 컨테이너를 사용하는 방법

  4. 4

    Android 라이브러리를 Java 라이브러리로 변경하는 방법

  5. 5

    EventEmitter 메모리 누수 감지 : CSV 데이터를 여러 모듈로 전달하는 적절한 방법?

  6. 6

    Google API 자바 스크립트 클라이언트 라이브러리를 Chrome 앱에로드하는 방법

  7. 7

    모든 서버 인스턴스에서 로컬 메모리 캐시를 업데이트하는 방법

  8. 8

    바인딩 라이브러리에서 Xamarin iOS 프로젝트에 메서드를 사용하는 방법

  9. 9

    Ubuntu 16.04 : 최신 라이브러리로 YubiKey 개인화 도구 (GUI)를 업데이트하는 방법은 무엇입니까?

  10. 10

    jquery 확인 라이브러리로 올바른 링크를 대상으로 지정하는 방법

  11. 11

    '라이브러리 누락'오류를 방지하는 방법 Linux

  12. 12

    OpenShift 온라인에서 "다운로드 가능한 카트리지"를 업데이트하는 방법

  13. 13

    PyKCS11 라이브러리로 서명 된 데이터를 확인하는 방법

  14. 14

    cppyy에서 라이브러리를로드하는 방법?

  15. 15

    cppyy에서 라이브러리를로드하는 방법?

  16. 16

    CMake로 라이브러리를 빌드하는 방법

  17. 17

    .NetOffice 라이브러리로 헤더를 추가하는 방법

  18. 18

    paper.js 라이브러리를로드하는 방법?

  19. 19

    내 프로그램에 메모리 누수가 없는지 확인하는 방법이 있습니까?

  20. 20

    foreach 라이브러리를로드하지 않고 사용하는 방법

  21. 21

    웹 사이트에서 라이브러리를 업데이트하는 방법은 무엇입니까?

  22. 22

    코드에서 메모리 누수를 방지하는 방법

  23. 23

    iOS에서 ARC 메모리 누수를 방지하는 방법

  24. 24

    라이브러리 누락으로 인해 믹서에 연결되지 않는 Pulseaudio를 해결하는 방법은 무엇입니까?

  25. 25

    라이브러리를 정적 / 공유 라이브러리가 아닌 내 앱 소스의 일부로 CMake 컴파일하는 방법은 무엇입니까?

  26. 26

    Android에서 공유 라이브러리로드를 지연하는 방법

  27. 27

    Ion 라이브러리를 사용하여 이미지를 다운로드하고 앱 디렉토리에 저장하는 방법

  28. 28

    Python Pandas 라이브러리로 데이터를 변경하는 방법

  29. 29

    Windows 개발 : 내 앱의 메모리 누수 여부를 확인하는 방법은 무엇입니까?

뜨겁다태그

보관