Android Kotlin:从自身/内部引用匿名对象(通过此)

Android Kotlin:从自身/内部引用匿名对象(通过此),android,kotlin,this,anonymous-class,Android,Kotlin,This,Anonymous Class,TL;DR 这些对象:某些类{}匿名对象无法通过此访问自身(这将导致外部对象)我如何访问它? 详细解释: 对于我的片段,我需要一个预绘制的侦听器。我称之为onCreateView。执行时,我希望在执行后删除侦听器。所以Java的做法会建议这样做 override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, val treeObserver = layout.viewTreeObserver

TL;DR 这些
对象:某些类{}
匿名对象无法通过
访问自身(这将导致外部对象我如何访问它?

详细解释:

对于我的片段,我需要一个预绘制的侦听器。我称之为onCreateView。执行时,我希望在执行后删除侦听器。所以Java的做法会建议这样做

  override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,    

  val treeObserver = layout.viewTreeObserver

  treeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
     override fun onPreDraw(): Boolean {
        layout.viewTreeObserver.removeOnPreDrawListener(this)
        ...
     }
  }

问题是,当查看
removeOnPreDrawListener(this)
时,
this
对象不是监听器,而是
myFragment$onCreateView$1@f019bf0

或者,我可以访问
this@MyFragment
直接返回对片段的引用


不过,这些选项似乎都不是我的
PreDrawListener
我如何从内部访问它(如果有)?

我真的不认为你有问题

这个
在匿名中指的是类本身,但它们从来没有名字。无法创建具有名称的匿名类。为了演示这一点,我编写了一些示例代码:

class TheClass{
    fun run(){
        val anon = object: Runnable {
            override fun run() {}
        }
        println(anon::class.java.simpleName)
        println(anon::class.java.name)
    }
}
其中打印:

run$anon$1
com.package.TheClass$run$anon$1
现在,这一切都很好,但它仍然不像你的。但是您可以看到它与包含的类、方法、变量以及表示它是匿名内部类的美元符号相匹配。这适用于第二个,即完整的。第一个只打印短名称,即方法、var名称,以及显示其匿名函数的美元符号

如果您对带数字的美元符号出现的原因感兴趣,请参阅。T

让我们展开它,去掉变量。显然,这是一段可怕的代码(而且内存效率很低,但这只是一个演示,所以不重要):

这将打印并匹配您的图案:

com.package.TheClass$run$anon$1
你已经看到了模式;现在,您可以开始“解码”得到的哈希:

myFragment // inside myFragment
$onCreateView // Inside a function
$1 // There is an anonymous class with a specific identifier
@f019bf0 // This is standard everywhere; just look up Object.toString()
我刚才试图证明的是:
这个
确实引用了您创建的匿名函数。匿名函数是匿名的。他们没有名字。它们使用
$number
作为标识符。因此,如果您有以下代码:

treeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
    override fun onPreDraw(): Boolean {
       layout.viewTreeObserver.removeOnPreDrawListener(this)
       ...
    }
 }
将引用侦听器,即使打印类可能会打印看起来令人困惑的内容。如果有什么东西坏了,那不是因为
这个
没有提到听者(因为它有)

而且,您的代码编译得很好。这里也没有类型不匹配。如果它引用了另一个对象,那么如果您将
this
传递给一个需要
onpredrawstener
的方法,它将不起作用


在Java中使用相同的代码会得到不同的结果。这是因为Kotlin将匿名函数编译为
Class$function$number
,而as Java将其编译为
Class$number
。如果它位于嵌套类中,则在Kotlin中显示为
Outer$Inner$function$number
,在Java中显示为
Outer$Inner$number

编译器的不同导致了不同的名称;Java不包含函数,而Kotlin包含函数。它位于
.class
文件名中,因此如果您构建项目并在文件资源管理器中查看所有操作系统的文件名(不要查看IntelliJ。它会为您反编译文件。请记住,您只是在查找名称,IntelliJ会将.class文件合并为一个文件以匹配原始源,从而将名称弄乱)



就像最后一个元一样,我打印类而不是打印对象。接口没有重写的toString方法,这意味着它默认为对象上的方法,该方法返回
getClass().getName()+“@”+Integer.toHexString(hashCode());
(可以找到原始代码)。
println(此)
println(this.toString())
相同,后者在对象中调用toString方法,打印类名。
println(this)
与打印对象或打印类相同

这在Kotlin中绝对有效,我刚刚尝试过。同样,android ktx库中实现的这一功能也有效。可能是您的设置有问题,或者您在错误的范围内?您可以发布一个可验证的最小示例吗?
myFragment$onCrea特维尤$1@f019bf0
是侦听器继承的
toString()
实现。您应该能够覆盖它(除了
onPreDraw
)看到它改变了。哇,goog解释。所以我只是误解了命名。非常感谢!这并没有解释当对象和包含类之间存在命名冲突时如何引用匿名对象,比如成员和同名的局部变量。为此,你需要像这样的@??,但不清楚是什么@Zoe很酷的解释。我在这里发布了一个类似的问题()。你能看一下并提供一些见解吗?
treeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
    override fun onPreDraw(): Boolean {
       layout.viewTreeObserver.removeOnPreDrawListener(this)
       ...
    }
 }