No need to cast the result of findViewById?

AndroidCastingFindviewbyid

Android Problem Overview


Recently I found that AndroidStudio reminds me to remove some class cast. I remember that in the old time, we have to cast the result of findViewById, but now it's not necessary.

The result of findViewById is still View, so i want to know why we don't need to cast the class?

I can't find any documents mentioned that, can anyone find any document?

Android Solutions


Solution 1 - Android

Starting with API 26, findViewById uses inference for its return type, so you no longer have to cast.

Old definition:

View findViewById(int id)

New definition:

<T extends View> T findViewById(int id)

So if your compileSdk is at least 26, it means that you can make use of this :)

Solution 2 - Android

In older versions:

AutoCompleteTextView name = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView);

From Android Studio 3.0 with SDK 26:

AutoCompleteTextView name = findViewById(R.id.autoCompleteTextView);

Solution 3 - Android

According to this article:

> The following function relies on Java’s generics automatic type inference in order to eliminate a need for manual casting:

protected <T extends View> T findViewById(@IdRes int id) {
    return (T) getRootView().findViewById(id);
}

Solution 4 - Android

Android Studio reminds to remove casting, if you use common attributes from View class, like visibility or some common methods, like onClick()

For example:

((ImageView) findViewById(R.id.image_car)).setVisibility(View.VISIBLE);

In this case you can simply write:

findViewById(R.id.image_car).setVisibility(View.VISIBLE);

Solution 5 - Android

Android 0, clean up casting

One of the things that google announce in IO 2017 is something that’s called ‘cast away’ :). Android developer don’t have to do a manual casting for findViewById(). For example the old way to get a text view using findViewById() would be something like this.

TextView txtDesc = (TextView) findViewById(R.id.textViewDesc);
txtDesc.setText(getString(R.string.info_angkot_description));

While the new way would be like this

TextView txtDesc = findViewById(R.id.textViewDesc);
txtDesc.setText(getString(R.string.info_angkot_description));

It’s a simple change. But for a seasoned programmer, a clean code like this can make you very happy and it helps with your coding mood :)

To be able to do this you only needed to set your project compiled sdk version to version 26 in your app build.gradle.

You can still target earlier sdk version too, so it’s a non-intrusive changes.

Now the real problem, how do you clean that old code that uses casting all this time. Especially when you have like hundreds of activity files. You can do it manually, or maybe hired an intern to do it . But luckily for all of those intern, android studio already prepared to help us with this.

When you put your caret (or click on the redundant casting) android studio will suggest 2 option to handle the redundant casting.

First it will suggest to remove that redundant cast or you can select clean up code. It will remove all the redundant cast for that file. This is better, but we want more. We don’t want to open each file and do this clean up one by one.

One of the things that make IntelliJ idea Special is that a feature that is called intent action. All you have to do is push ctrl+shift+A and then type clean. And select Code Clean up action, and select the whole project scope. With this few simple steps your code will be a whole lot cleaner.

One important point is that you do this with some code versioning system. This way you can compare the changes that being made by the intent action and revert any files you want.

Copied from original post:

https://medium.com/@abangkis/android-0-clean-up-casting-c30acec56cef

Solution 6 - Android

In the source code of ViewGroup, there is a cast of the return argument. So there is no need to cast again:

@Nullable
public final <T extends View> T findViewById(@IdRes int id) {
    if (id == NO_ID) {
        return null;
    }
    return findViewTraversal(id);
}

@Override
protected <T extends View> T findViewTraversal(@IdRes int id) {
    if (id == mID) {
        return (T) this;  //###### cast to T
    }

    final View[] where = mChildren;
    final int len = mChildrenCount;

    for (int i = 0; i < len; i++) {
        View v = where[i];

        if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
            v = v.findViewById(id);

            if (v != null) {
                return (T) v; //###### cast to T
            }
        }
    }

    return null;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEric ZhaoView Question on Stackoverflow
Solution 1 - AndroidEduard B.View Answer on Stackoverflow
Solution 2 - AndroidMidhunView Answer on Stackoverflow
Solution 3 - AndroidzeroDividerView Answer on Stackoverflow
Solution 4 - AndroidTimView Answer on Stackoverflow
Solution 5 - AndroiddaliaessamView Answer on Stackoverflow
Solution 6 - AndroidactivityView Answer on Stackoverflow