Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternate and fast replacement of findViewById in android

How I can avoid using findViewById in my app. Layout is very complicated and findViewById traverses its tree to find view which takes time and it is used several times.

like image 295
Qasim Hasnain Avatar asked May 25 '17 10:05

Qasim Hasnain


2 Answers

First, you must edit your application’s build.gradle file and add the following into the android block:

android {
    …
    dataBinding.enabled = true
}

The next thing is to change the layout file by making the outer tag instead of whatever ViewGroup you use:

<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools">
    <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingLeft="@dimen/activity_horizontal_margin"
            android:paddingRight="@dimen/activity_horizontal_margin"
            android:paddingTop="@dimen/activity_vertical_margin"
            android:paddingBottom="@dimen/activity_vertical_margin"
            tools:context=".MainActivity">

        <TextView
                android:id="@+id/hello"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>

    </RelativeLayout>
</layout>

The layout tag tells Android Studio that this layout should take the extra processing during compilation time to find all the interesting Views and note them for the next step. All layouts without that outer layout tag will not get the extra processing step, so you can sprinkle these into new projects wherever you like without changing anything in the rest of your application.

The next thing you have to do is to tell it to load your layout file differently at runtime. Because this works all the way back to the Eclair release, there is no reliance on new framework changes to load these preprocessed layout files. Therefore, you do have to make a slight change to your loading procedure.

From an Activity, instead of:

setContentView(R.layout.hello_world);
TextView hello = (TextView) findViewById(R.id.hello);
hello.setText("Hello World"); // for example, but you'd use resources, right?

You load it like this:

HelloWorldBinding binding = DataBindingUtil.setContentView(this, R.layout.hello_world);
binding.hello.setText("Hello World"); // you should use resources!

Here you can see that a class, HelloWorldBinding, was generated for the hello_world.xml layout file, and the View with the ID @+id/hello was assigned to a final field hello that you can use. No casting, no findViewById.

It turns out that this mechanism for accessing views is not only much easier than findViewById, but can also be faster! The binding process makes a single pass on all Views in the layout to assign the views to the fields. When you run findViewById, the view hierarchy is walked each time to find it.

One thing you will see is that it transforms your variable names into camel case (just like hello_world.xml becomes the class HelloWorldBinding), so if you gave it the ID @+id/hello_text, then the field name would be helloText.

When you’re inflating your layouts for RecyclerView, ViewPager, or other things that aren’t setting the Activity contents, you’ll want to use the generated type-safe methods on the generated class. There are several versions that match the LayoutInflater, so use the one that is most appropriate for your use. For example:

HelloWorldBinding binding = HelloWorldBinding.inflate(
    getLayoutInflater(), container, attachToContainer);

If you aren’t attaching the inflated View to the containing ViewGroup, you’ll have to get access to the inflated View hierarchy. You can do this from the getRoot() method of the binding:

linearLayout.addView(binding.getRoot());
like image 180
John Simon Avatar answered Oct 20 '22 00:10

John Simon


Another choice is Kotlin's Android extensions.

// Using R.layout.activity_main from the main source set
import kotlinx.android.synthetic.main.activity_main.*

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

        // Instead of findView(R.id.textView) as TextView
        textView.setText("Hello, world!")
    }
}

https://kotlinlang.org/docs/tutorials/android-plugin.html

like image 42
Lisa Wray Avatar answered Oct 19 '22 22:10

Lisa Wray