小部件伴随对象中的 kotlin Lateinit - 泄漏警告

问题描述 投票:0回答:1

所以我对 kotlin 和 Android 都很陌生。 我写了一个应用程序,它完全按照我想要的方式工作,除了 它给了我一个编译器警告:

 'Do not place Android context classes in static fields; this is a memory leak'

在我的一个文件中:

lateinit var appContext: Context private set
lateinit var appRez: Resources private set

class HackJob : Application() {
    override fun onCreate() {
        super.onCreate()
        appContext = applicationContext
        appRez = resources
        val clientthread = ClientThread()  //these three can be collapsed into one line
        val maThread = Thread(clientthread)
        maThread.start()
    }
    internal class ClientThread : Runnable { 

        ContextCompat.getMainExecutor(appContext).execute /* command = */  {
            MainActivity.otv.setBackgroundColor(Color.RED)
            MainActivity.osb.visibility = View.VISIBLE
        }

    }
}

在另一个文件中:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // create a value that is linked to a button called (id) start in the layout

        val tv: TextView = findViewById(R.id.rcvdData)
        val startButton = findViewById<Button>(R.id.start)
...
        otv = tv
        osb = startButton
...
   }
   companion object {
        lateinit var otv: TextView
        lateinit var osb: Button
   }
}

正如我所说,即使屏幕旋转,它似乎也能正常工作。 完全按照我想要的方式做!

我真的在这里泄漏内存了吗? 我应该对泄漏警告有多担心?

当我旋转屏幕时,大概 android 正在拆除 Activity,并且 重新实例化它旋转,但我的同伴变量(otv 和 osb)在 onCreate 中更新!这是否意味着旧值会失去引用计数并被GCed?

我承认我不太明白我在做什么,我只是不断尝试直到成功为止。 这段代码的味道有多糟糕?该应用程序非常敏捷并且运行良好!

android kotlin memory-leaks companion-object
1个回答
0
投票

即使屏幕旋转,它似乎也能正常工作

有问题。

我真的在这里泄漏内存了吗?

是的。对于您问题中的文字代码的影响很小,但如果您打算更改该代码,这种影响可能会变得更糟。

当我旋转屏幕时,大概 android 正在拆除该 Activity,并重新实例化它旋转,但我的同伴变量(otv 和 osb)在 onCreate 中更新!这是否意味着旧值会失去引用计数并被GCed?

是的。但是,请记住,除了配置更改之外,还有其他方法可以销毁 Activity,例如通过调用

finish()
或通过系统 BACK 导航。在这些情况下,您就会泄漏内存。此外,您可以创建 2 个以上
MainActivity
实例,在这种情况下,这些属性将仅指向最近实例化的
MainActivity
,这可能会导致问题。


你的很多麻烦都集中在这个:

    internal class ClientThread : Runnable { 

        ContextCompat.getMainExecutor(appContext).execute /* command = */  {
            MainActivity.otv.setBackgroundColor(Color.RED)
            MainActivity.osb.visibility = View.VISIBLE
        }

    }

我真诚地希望没有任何书籍或课程可以演示这种技术,因为它有几个问题:

  1. 您假设这些属性(
    otv
    osb
    )在引用它们之前已被填充。对此没有任何保证。
  2. 您假设这些属性指向
    MainActivity
    的正确实例。如果有 2 个以上
    MainActivity
    实例,则可能不正确。
  3. 您假设这些属性指向
    MainActivity
    的未销毁实例。尽管很有可能,但无法保证这一点。
  4. 这种编程方法首先导致您创建那些可能存在泄漏的属性。
© www.soinside.com 2019 - 2024. All rights reserved.