lundi 4 octobre 2021

Android Development Basics: How to add View Binding to an Android Gradle project

Most Android developers are probably familiar with the classic findViewById() method. Pass it an ID of one of the Views in your XML layout and it’ll return a reference to the inflated version of that View. That’s all assuming you passed the right ID though, and that the View actually exists. findViewById() has no checks built in to prevent you from trying to retrieve a View you can’t retrieve. Enter View Binding.

Instead of using findViewById() on each View you want, View Binding automatically generates a binding class for each layout XML. Each View with an ID is automatically added to the class, so you can reference them directly.

Adding View Binding to an Android Gradle project is super simple.

Gradle Setup

View Binding is enabled at the module level in Gradle. If you have multiple modules, you’ll need to enable it individually for each one.

In the android block in your module-level build.gradle, add the option to enable View Binding.

android {
    ...

    buildFeatures {
        viewBinding true
    }
}

There may be a warning about illegal access, but that’s a lint bug and can be safely ignored.

Sync the project and View Binding will be enabled. It’s that easy.

Using View Binding

There are a few ways to use View Binding, but before any of that happens, let’s talk about how the binding classes are generated.

Class Name Syntax

Say you have a layout XML named some_layout.xml. Its corresponding binding class will be named SomeLayoutBinding. That pattern holds for all files.

Each word (separated by underscores in the file name) will be capitalized, and the underscores will be removed. “Binding” then gets added to the end.

Instantiating with Existing View

If you’ve already inflated the layout file and you have a reference to the root of the layout, you can tell the View binding class to use the existing layout.

Kotlin:

val binding = SomeLayoutBinding.bind(someLayoutRoot /* should be a View instance */)

Java:

SomeLayoutBinding binding = SomeLayoutBinding.bind(someLayoutRoot /* should be a View instance */);

For example, if you wanted to use the binding class in a Fragment, it would look something like this.

Kotlin:

class SomeFragment : Fragment(R.layout.some_layout) {
    //Lazy initialization means bind() won't be called until "binding" is referenced.
    private val binding by lazy { SomeLayoutBinding.bind(view) }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        
        //Once this method is called, you can start using the binding.
    }
}

Java:

public class SomeFragment extends Fragment {
    private SomeLayoutBinding binding = null;

    public SomeFragment() {
        super(R.layout.some_layout);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
   
        //Initialize the binding.
        binding = SomeLayoutBinding.bind(view);
    }
}

Instantiating with New View

The binding class can also take care of inflating the layout for you.

Kotlin:

val binding = SomeLayoutBinding.inflate(layoutInflater /* should be a LayoutInflater instance */)

Java:

SomeLayoutBinding binding = SomeLayoutBinding.inflate(layoutInflater /* should be a LayoutInflater instance */);

This method is useful in both Fragments and Activities.

An example Fragment would look something like the following.

Kotlin:

class SomeFragment : Fragment() {
    private val binding by lazy { SomeLayoutBinding.inflate(LayoutInflater.from(requireContext())) }

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) {
        //The "root" of the binding class is the root of its layout.
        return binding.root
    }
}

Java:

public class SomeFragment extends Fragment {
    private SomeLayoutBinding binding = null;

    @Override
    public void onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        //Initialize the binding.
        binding = SomeLayoutBinding.inflate(inflater);
        //The "getRoot()" method of the binding class returns the root of the layout.
        return binding.getRoot();
    }
}

An example Activity would look something like the following.

Kotlin:

class SomeActivity : AppCompatActivity() {
    private val binding by lazy { SomeLayoutBinding.inflate(layoutInflater) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        //This is equivalent to calling "setContentView(R.layout.some_layout)" but allows use of the binding class.
        setContentView(binding.root)
    }
}

Java:

public class SomeActivity extends AppCompatActivity {
    private SomeLayoutBinding binding = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //Instantiate the binding.
        binding = SomeLayoutBinding.inflate(getLayoutInflater());
        //This is equivalent to calling "setContentView(R.layout.some_layout)" but allows use of the binding class.
        setContentView(binding.getRoot());
    }
}

Referencing Views

Now that the View binding class is set up and ready to use, it’s time to actually use it.

Let’s say the contents of the some_layout.xml are something like the following:

<LinearLayout
    android:id="@+id/root_view"
    ...>
    <FrameLayout
        android:id="@+id/some_frame_layout"
        ...
        />
    <ImageView
        android:id="@+id/some_imageview"
        ...
        />
    <LinearLayout
        android:id="@+id/inner_linear"
        ...>
        <ImageView
            android:id="@+id/inner_imageview"
            ...
            />
    </LinearLayout>
</LinearLayout>

There are a lot of IDs there to reference in code. But as long as you have the binding class instantiated, referencing will be easy.

In Kotlin, Views are referenced by variables matching their IDs, with some changes. Underscores are removed and the resulting string is camel-cased. For example, to reference some_frame_layout from code, you’d use binding.someFrameLayout. The someFrameLayout variable will be an instance of FrameLayout.

val someFrameLayout: FrameLayout = binding.someFrameLayout

In Java, Views are referenced by getter methods matching their IDs, with a similar format to Kotlin. For example, to reference some_frame_layout, you’d use binding.getSomeFrameLayout(). The method will return an instance of FrameLayout.

FrameLayout someFrameLayout = binding.getSomeFrameLayout();

The View references are also flattened in the binding. Referencing inner_imageview is the same as referencing some_frame_layout.

Conclusion

As I’m sure you can see, View Binding in Android is both easy to implement and easy to use. In many cases, it’s easier to use than findViewById().

For more details on implementing View Binding, along with some examples, check out Google’s official documentation.

The post Android Development Basics: How to add View Binding to an Android Gradle project appeared first on xda-developers.



from xda-developers https://ift.tt/3uCf6zy
via IFTTT

Aucun commentaire:

Enregistrer un commentaire