使用数据存储区防止内存泄漏的最佳实践是什么? [英] What's the best practice to prevent memory leaks using Datastore?

查看:101
本文介绍了使用数据存储区防止内存泄漏的最佳实践是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试存储&使用数据存储首选项alpha07获取数据,一切正常,我在数据存储中遇到了内存泄漏问题

I try to store & get data using a datastore-preference alpha07, everything working fine, I got some memory leak issue in the datastore

使用数据存储区防止内存泄漏的最佳做法是什么?

What's the best practice to prevent memory leaks using Datastore?

这是我的示例代码:

// Preferences DataStore
    implementation "androidx.datastore:datastore-preferences:1.0.0-alpha07"
// Leakcanary find memory leak
    debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.6'

UserManager.kt

UserManager.kt

import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map

class UserManager(val dataStore: DataStore<Preferences>) {

    //Create some keys
    companion object {
        val USER_AGE_KEY = intPreferencesKey("USER_AGE")
        val USER_FIRST_NAME_KEY = stringPreferencesKey("USER_FIRST_NAME")
        val USER_LAST_NAME_KEY = stringPreferencesKey("USER_LAST_NAME")
        val USER_GENDER_KEY = booleanPreferencesKey("USER_GENDER")
    }

    //Store user data
    suspend fun storeUser(age: Int, fname: String, lname: String, isMale: Boolean) {
        dataStore.edit {
            it[USER_AGE_KEY] = age
            it[USER_FIRST_NAME_KEY] = fname
            it[USER_LAST_NAME_KEY] = lname
            it[USER_GENDER_KEY] = isMale

        }
    }

    //Create an age flow
    val userAgeFlow: Flow<Int?> = dataStore.data.map {
        it[USER_AGE_KEY]
    }

    //Create a fname flow
    val userFirstNameFlow: Flow<String?> = dataStore.data.map {
        it[USER_FIRST_NAME_KEY]
    }

    //Create a lname flow
    val userLastNameFlow: Flow<String?> = dataStore.data.map {
        it[USER_LAST_NAME_KEY]
    }

    //Create a gender flow
    val userGenderFlow: Flow<Boolean?> = dataStore.data.map {
        it[USER_GENDER_KEY]
    }

}

User.kt

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.preferencesDataStore

// At the top level of your kotlin file:
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "user_prefs")

SignInFragment.kt

SignInFragment.kt

 //Get reference to our userManager class
               var userManager = UserManager(requireContext().dataStore)
        
                //Stores the values
                lifecycleScope.launch {
                    userManager.storeUser(1, "android", "studio", true)
                }

HomeFragment.kt

HomeFragment.kt

var userManager = UserManager(requireContext().dataStore)
       userManager.userAgeFlow.asLiveData().observe(requireActivity(), {
            if (it != null) {
                age = it
                //tv_age.text = it.toString()
            }
        })

内存泄漏问题:

以下解决方案不起作用我尝试过,但即使尝试此解决方案,我仍然会漏水,在这种情况下,Fragment的生命周期应将观察者与组件的生命周期绑定在一起.改用viewLifeCycleOwner绑定观察者.

Below solution not working I tried, still I am getting leaks even tried this solution, Observer should be bind with component's lifecycle in this case Fragment's lifecycle . Use viewLifeCycleOwner instead to bind the observer.

HomeFragment.kt

HomeFragment.kt

 var userManager = UserManager(viewLifecycleOwner.dataStore)
           userManager.userAgeFlow.asLiveData().observe(viewLifeCycleOwner, {
                if (it != null) {
                    // age = it
                    // tv_age.text = it.toString()
                }
            })

引用屏幕截图(再次复制)

Ref screenshot (again replicated)

推荐答案

建议的修复程序

使用您的 Activity Fragment的上下文确实很麻烦,实际上并不需要这样做.相反,如果您传递应用程序的全局上下文( applicationContext ),则 DataStore 不会泄漏任何UI上下文,并将处理您的 Preferences 请求独立于其启动的UI组件的生命周期.

Suggested fix

Using your Activity's or Fragment's context is indeed fishy, and actually there's no need to do so. Instead, if you pass a global context of your application (applicationContext), then DataStore won't leak any UI contexts and will process your Preferences requests independently from the lifecycle of the UI component on which they start.

在您的 Fragments 中,输入以下内容:

In your Fragments, write the following:

...
var userManager = UserManager(requireContext().applicationContext.dataStore) 
...

在您的 MainActivity 中,它会更加简单:

In your MainActivity, it will be even simpler:

...
var userManager = UserManager(applicationContext.dataStore) 
...

结果

这就是检测到的泄漏数量:

Result

That's how many leaks have been detected:

这篇关于使用数据存储区防止内存泄漏的最佳实践是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆