Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Data Binding Programmatically Instantiated View

The Android documentation does a great job of describing how one can create a binding class using a layout xml file. But I have a couple of questions.

Is there a way to create a data binding class for a custom view that is instantiated programmatically? For example, lets say I have two custom view classes and I want to bind the same view model object to them programmatically without using any xml. The classes are as follows:

class MyViewModel {
}

class MyCustomView extends View {
}

class MyAnotherCustomView extends MyCustomView {
}

Now lets say I instantiate MyCustomView/MyAnotherCustomView using:

MyCustomView customView = new MyCustomView(context);

How do I go about using data binding in this case? Is this possible using the official Android data binding framework? If not, what other frameworks/libraries are available or recommended to achieve this?

My second question is a follow up of the first question. Lets say it is not possible to achieve what I want in my first question. Then, I will have to define a my_custom_view.xml file. This will look something like this:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
   <data>
       <variable name="user" type="com.example.User"/>
   </data>
   <com.example.name.MyCustomView
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       android:text="@{user.firstName}"/>
</layout>

Now, if I want to use MyAnotherCustomView which is a subclass of MyCustomView keeping the binding logic the same, will I have to create a new xml file my_another_custom_view.xml just to replace MyCustomView with MyAnotherCustomView to define the same binding?

like image 821
androholic Avatar asked Dec 01 '16 18:12

androholic


1 Answers

The answer to the first question is "No." Android data binding requires the XML to generate the binding classes.

In your second question, you offer a solution that will work. If you go that route, one way to do it is to use the ViewDataBinding base class setters to set your variables. I can imagine a method like this:

public void addCustomView(LayoutInflater inflater, ViewGroup container, User user) {
    ViewDataBinding binding = DataBindingUtil.inflate(inflater,
        this.layoutId, container, true);
    binding.setVariable(BR.user, user);
}

Here, I've assumed the selection of which custom View is determined by a field layoutId. Each possible layout will have to define a user variable of type User.

I don't know the particulars of your use, but if you want to dynamically choose which custom view to load, you could use a ViewStub. You could also do the same thing with just visibility if you don't have any tremendous overhead in loading your custom Views.

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
   <data>
       <import type="android.view.View"/>
       <variable name="user" type="com.example.User"/>
       <variable name="viewChoice" type="int"/>
   </data>
   <FrameLayout ...>
       <!-- All of your outer layout, which may include binding
            to the user variable -->
       <ViewStub android:layout="@layout/myCustomView1"
                 app:user="@{user}"
                 android:visiblity="@{viewChoice == 1} ? View.VISIBLE : View.GONE"/>
       <ViewStub android:layout="@layout/myCustomView2"
                 app:user="@{user}"
                 android:visiblity="@{viewChoice == 2} ? View.VISIBLE : View.GONE"/>
    </FrameLayout>
</layout>
like image 144
George Mount Avatar answered Oct 10 '22 06:10

George Mount