How does findViewById() method work in activity? - android

When I add a view to xml (layout) of my activity, it takes an id, so I can use that id in code of activity to recognize it and change my view if I like. Android make an R.class as an intermediate between my activity code an my layout(xml), so I use R.class for example:
findViewById(R.id.textView);
But how does android find it is a TextView? For example, if I write:
Button b = findViewById(R.id.textView);
I get an error. From where does it find I write it wrong?
I mean in R.class it define my id so android know a new id is defined in my xml, and I use it to return an object of View class or class extend View. But how does it find I am writing wrong and it is not a button, before I run the program (in compile time)?

Android Studio runs Android lint checks on your code, and there's the WrongViewCast check to detect such issues and report them as errors:
WrongViewCast
-------------
Summary: Mismatched view type
Priority: 9 / 10
Severity: Error
Category: Correctness
Keeps track of the view types associated with ids and if it finds a usage of
the id in the Java code it ensures that it is treated as the same type.
Source: http://tools.android.com/tips/lint-checks

If your view, that is returned by findViewById(R.id.ID), doesn't cast to the field you're assigning the view to, your code won't even compile! Android Studio checks your assigned variables and tries to cast them in real-time, but if that fails, because you made a mistake, your Activity.java can't compile! This is just a way of how this IDE operates.
Some time ago, you needed to cast the view manually, like this:
(TextView) findViewById(R.id.text_view)
But this is not necessary anymore.

Related

Instrumentation test doesn't match view ids from hierarchy

In short, I'm trying to match view with ID like R.id.signCheckbox using Espresso. When I try to match that view I will get NoMatchingView exception when it's clear that view is present.
After some debugging, I've found out that inside my test class when I eval R.id.signCheckbox I'll get ID: -1000984. Inside cause of the NoMatchingViewException you can actually read whole view hierarchy in some format. There I've found that checkbox has different ID 2131362821. I've read the project R.java and it's also assigning 2131362821 to R.id.signCheckbox.
So when I match withId(2131362821) it's actually working. Why it's not working with R.id.signCheckbox and where that -1000984 id comes from?
It looks like the good old Invalidate/Restart/Clean/Rebuild fixed the problem.
The IDs are still negative (like -1000984) not matching the R.java IDs, but Espresso will successfully match the views.

Why does the R class not contain the field type?

Whenever we want to inflate a view or get a resource we have to cast it in run-time. views, for example, are used like so:
In the past, we would have needed to cast it locally
(RelativeLayout) findViewById(R.id.my_relative_layout_view)
Now, we use generics
findViewById<RelativeLayout>(R.id.my_relative_layout_view)
my question is why doesn't the compiler(or whoever generates the R class) doesn't also keep some kind of a reference to the type of the element(doesn't matter if it's a string or an int or any other type) that way casting problems should not occur
We cannot really speculate on that, that would be a design choice.
It might be that they wanted to avoid bloating the APK. Every ID would need a full package name to the class. So would each ID in android.R too. Since R is packaged in every APK.
Solutions
However, if you are using Kotlin, you can even do away with the generics check. Kotlin will determine it automatically.
val view = findViewById(R.id.my_relative_layout_view)
view.method()
Or event simpler, if you use synthetics:
my_relative_layout_view.method()
Also, if you are using data bindings, you can just access it like this:
binding.my_relative_layout_view.method()

Unexpected implicit cast to CharSequence: layout tag was TextView

Android Studio shows the error
Unexpected implicit cast to CharSequence: layout tag was TextView
at this code
findViewById<TextView>(R.id.tv_name).text = "text"
If I write
(findViewById<TextView>(R.id.tv_name) as TextView).text = "text"
Everything is fine.
The question is why this happens? Doesn't findViewById<TextView> already have type TextView?
You can use Kotlin Android Extensions
Kotlin Android Extensions are Kotlin plugin that will allow to recover views from Activities, Fragments and Views in an amazing seamless way.
you can directly use
tv_name.text = "text"
no need of findViewById
Reference
https://antonioleiva.com/kotlin-android-extensions/
You can directly use all the views using DataBinding. Less code and very advance feature of android. There are many articles for Android DataBinding.
https://developer.android.com/topic/libraries/data-binding/index.html
This is only warning of lint. You can ignore it with #SuppressLint("WrongViewCast"). This happend because of usage of generic types from Java in Kotlin.
First of, Kotlin under the hood, just wraps up java findViewById method. Up to API 26 explicit cast was neccessary as method returned View, but now it returns . Check this answer No need to cast the result of findViewById?
If you dive into the source code, through invokations of findViewById, you'll get to Window.findViewById method, and if you look to description of it in documentation, you'll see one note there, which says that: "In most cases -- depending on compiler support -- the resulting view is automatically cast to the target class type. If the target class type is unconstrained, an explicit cast may be necessary." https://developer.android.com/reference/android/view/Window.html#findViewById(int)
I don't know what "unconstrained" actually means in this context, but as i understand, in some cases cast is required in others is not, so just deal with it. For example, i tried to add some param to ImageView and compiler didn't show any kind of warnings:
findViewById<ImageView>(R.id.iv).adjustViewBounds = true

How to find a code behind a view in hierarchyviewer

Android hierarchyviewer shows a ID for each view in the tree view.
The ID is a # sign followed by a number, e.g #4051d698
In android documentation the purpose of this number is explained as "pointer to view object".
Assuming one has the sources of a very big android project like AOSP.
How can one figure out what is the java source code behind the view by using this ID?
Is there a method I can invoke that tells me what is the R.java entry that is bound to this pointer?
How can one figure out what is the java source code behind the view by using this ID?
You can't, at least without a debugger. If you are used to C/C++ development, that hexadecimal value is roughly analogous to a pointer. Just because you have a pointer to a hunk of RAM in C/C++ does not mean that you can determine the source code behind the object resident at that pointer.
Now, it is possible that there is a way in a debugger to supply this hex value and the debugger will match that up to an object and source code. I am not an Eclipse expert, or an expert on another other IDE debuggers, to know whether or not there is a means to do this. However, even if can do this, it will probably only give you the source of the class of the object (e.g., if the View is a ListView, it might send you to the ListView source code), not the source code of what created the object.
Is there a method I can invoke that tells me what is the R.java entry that is bound to this pointer?
First, R.java is not "bound" to any pointers.
Second, the View in question may not have come from an inflated layout. It might have been created directly in Java code instead.
If the View has an "View object ID" (e.g., id/content), that can better help you find where it came from, as that will be an android:id value, possibly from your layout resources.

Unable to find components using the findViewById method in Android

I'm attempting to create an Activity and unfortunately every time I want to grab one of my XML components it gives me a RunTimeException (NullPointer).
Anytime I use code such as:
TextView tv = (TextView) findViewById(R.id.myView); //I get the exception
The same happens for any components I attempt to find with that method. I can't quite figure out why. I know it isn't due to the Activity not being in the Manifest because it's the only Activity in the test app I made. (The one set up by default).
Oddly I can still use setContentView(R.id.myView). It just doesn't seem to want to find anything when using the findViewById method.
Info that might be of use:
I am currently using NetBeans as my IDE.
I have done multiple 'clean and builds' as was suggested in another question. Android -findViewById question
Has anyone run into this issue before? If so, what was the solution?
If need be, I can provide sample code of when this is happening.
Don't pass in a view ID to setContentView, pass in a layout resource ID:
setContentView(R.layout.layout_name);
If you still have problems, post your layout file.
It is very sure that you R.java is not properly generated.
Delete R.Java in netbeans IDE and Re-build the project.
Hope it resolves your query.

Categories

Resources