This version of View.findViewById()
returns the most specific concrete subtype of View
:
protected <T extends View> T findViewById(@IdRes int id) {
return (T) getRootView().findViewById(id);
}
How does it work? Specifically, how can the type be inferred at compile-time when the id
is looked up at runtime? Does it have to do with the annotation?
This differs from questions with similar titles, which are about the use of findViewById()
:
I would like to know why it works.
It can't be inferred. It uses a cast - return (T)
. The caller is responsible for ensuring that the type T matches the type of view being located. If they get this wrong, the operation will fail with a ClassCastException
.
The type can be either explicitly specified, i.e.
this.<TextView>findViewById(R.id.someTextView)
(excuse my syntax if I've got this wrong - I mostly deal in Kotlin now)
or it can be inferred from the destination:
TextView foundView = findViewById(R.id.someTextView)
but in either case, the responsibility lies with the caller.
The Android toolchain may do further work to cross-reference layout XML with the code, and produce warnings or failures within your IDE, but this is a compile-time layer on top of what Java performs at runtime.
It has nothing to do with the @IdRes
annotation, which is there to assert - again at compile time - that the id
parameter is a reference to the ID of some XML-based entity, and not simply any integer value.