0

I'm trying to use Android Databinding in my Android app. I've an Object Outlet if I initialize the object without any data. Everything works fine. And all data are well collected. But, if I initialize the Object with data and passing it to the layout, it crashes the app with complains of Invoking Interface method on Null Views. This is my Layout file below:

    <?xml version="1.0" encoding="utf-8"?>
    <layout xmlns:android="http://schemas.android.com/apk/res/android">

        <data>
            <import type="java.util.List"/>
            <import type="android.view.View" />
            <variable
                name="outlet"
                type="co.deliveryscience.dangote.Network.model.Outlet.Create.Outlet"/>
        </data>

        <android.support.v4.widget.NestedScrollView
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">

                <android.support.v7.widget.CardView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginBottom="32dp"
                    android:layout_marginLeft="64dp"
                    android:layout_marginRight="64dp"
                    android:layout_marginTop="32dp"
                    android:background="#FFF"
                    android:animateLayoutChanges="true"
                    app:cardCornerRadius="4dp"
                    app:elevation="5dp">

                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="vertical"
                        android:paddingBottom="16dp"
                        android:paddingLeft="16dp"
                        android:paddingRight="16dp"
                        android:paddingTop="16dp"
                        android:animateLayoutChanges="true">

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            style="@style/HeaderText"
                            android:text="@string/personal_information"
                            android:layout_marginBottom="8dp"
                            android:layout_marginTop="16dp"/>

                        <View
                            android:layout_width="match_parent"
                            android:layout_height="0.5dp"
                            android:background="@color/gray_semi_transparent"
                            android:layout_marginBottom="32dp"/>

                        <LinearLayout
                            android:id="@+id/layoutCreate"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:orientation="vertical"
                            android:layout_marginBottom="32dp">

                            <TextView
                                android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:text="@string/name_of_outlet"
                                android:layout_marginBottom="8dp"/>

                            <EditText
                                android:id="@+id/nameOfOutlet"
                                android:layout_width="match_parent"
                                android:layout_height="55dp"
                                android:inputType="textCapWords"
                                android:singleLine="true"
                                android:imeOptions="actionNext"
                                android:text='@{outlet.name ?? ""}'
                                android:addTextChangedListener="@{outlet.onNameChanged}"
                                android:nextFocusDown="@+id/address"/>

                        </LinearLayout>

                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:orientation="horizontal"
                            android:baselineAligned="false">

                            <LinearLayout
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:orientation="vertical"
                                android:layout_marginRight="8dp"
                                android:layout_marginEnd="8dp">

                                <TextView
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="@string/ownerfirstname"
                                    android:layout_marginBottom="8dp"/>

                                <EditText
                                    android:id="@+id/fName"
                                    android:layout_width="match_parent"
                                    android:layout_height="55dp"
                                    android:layout_marginBottom="16dp"
                                    android:inputType="textCapWords"
                                    android:singleLine="true"
                                    android:imeOptions="actionNext"
                                    android:text="@{outlet.firstName}"
                                    android:addTextChangedListener="@{outlet.onFirstNameChanged}"
                                    android:nextFocusRight="@+id/lName"/>

                            </LinearLayout>

                            <LinearLayout
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:orientation="vertical"
                                android:layout_marginLeft="8dp"
                                android:layout_marginStart="8dp">

                                <TextView
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="@string/ownerlastname"
                                    android:layout_marginBottom="8dp"/>

                                <EditText
                                    android:id="@+id/lName"
                                    android:layout_width="match_parent"
                                    android:layout_height="55dp"
                                    android:layout_marginBottom="16dp"
                                    android:inputType="textCapWords"
                                    android:text='@{outlet.lastName == null ? "" : outlet.lastName}'
                                    android:addTextChangedListener="@{outlet.onLastNameChanged}"
                                    android:singleLine="true"
                                    android:imeOptions="actionNext"
                                    android:nextFocusDown="@+id/nameOfOutlet"/>

                            </LinearLayout>

                        </LinearLayout>

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            style="@style/HeaderText"
                            android:text="@string/contact_information"
                            android:layout_marginBottom="8dp"
                            android:layout_marginTop="16dp"/>

                        <View
                            android:layout_width="match_parent"
                            android:layout_height="0.5dp"
                            android:background="@color/gray_semi_transparent"
                            android:layout_marginBottom="32dp"/>

                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="@string/address"
                            android:layout_marginBottom="8dp"/>

                        <EditText
                            android:id="@+id/address"
                            android:layout_width="match_parent"
                            android:layout_height="55dp"
                            android:layout_marginBottom="16dp"
                            android:inputType="textPostalAddress"
                            android:text='@{outlet.address == null ? "" : outlet.address}'
                            android:addTextChangedListener="@{outlet.onAddresChanged}"
                            android:imeOptions="actionNext"
                            android:nextFocusDown="@+id/lga"/>

                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:orientation="horizontal"
                            android:layout_marginBottom="16dp"
                            android:baselineAligned="false">

                            <LinearLayout
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:orientation="vertical"
                                android:layout_weight="1"
                                android:layout_marginRight="8dp"
                                android:layout_marginEnd="8dp">

                                <TextView
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="@string/lga"
                                    android:layout_marginBottom="8dp"/>

                                <AutoCompleteTextView
                                    android:id="@+id/lga"
                                    android:layout_width="match_parent"
                                    android:layout_height="55dp"
                                    android:imeOptions="actionNext"
                                    android:inputType="textCapWords"
                                    android:text="@{outlet.lga}"
                                    android:singleLine="true"
                                    android:nextFocusRight="@+id/state"/>

                            </LinearLayout>

                            <LinearLayout
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:orientation="vertical"
                                android:layout_weight="1"
                                android:layout_marginStart="8dp"
                                android:layout_marginLeft="8dp">

                                <TextView
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="@string/state"
                                    android:layout_marginBottom="8dp"/>

                                <AutoCompleteTextView
                                    android:id="@+id/state"
                                    android:layout_width="match_parent"
                                    android:layout_height="55dp"
                                    android:imeOptions="actionNext"
                                    android:inputType="textCapWords"
                                    android:singleLine="true"
                                    android:nextFocusDown="@+id/phoneNumber1" />

                            </LinearLayout>

                        </LinearLayout>

                        <LinearLayout
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:orientation="horizontal"
                            android:layout_marginBottom="16dp"
                            android:baselineAligned="true">

                            <LinearLayout
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:layout_marginRight="8dp"
                                android:layout_marginEnd="8dp"
                                android:orientation="vertical">

                                <TextView
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="@string/phone_number_1"
                                    android:layout_marginBottom="8dp"/>

                                <EditText
                                    android:id="@+id/phoneNumber1"
                                    android:layout_width="match_parent"
                                    android:layout_height="55dp"
                                    android:layout_marginBottom="16dp"
                                    android:inputType="phone"
                                    android:imeOptions="actionNext"
                                    android:addTextChangedListener="@{outlet.onPhoneNumberChanged}"
                                    android:text="@{outlet.phoneNumber}"
                                    android:singleLine="true"
                                    android:nextFocusDown="@+id/phoneNumber2"/>

                            </LinearLayout>

                            <LinearLayout
                                android:layout_width="0dp"
                                android:layout_height="wrap_content"
                                android:layout_weight="1"
                                android:layout_marginLeft="8dp"
                                android:layout_marginStart="8dp"
                                android:orientation="vertical">

                                <TextView
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="@string/phone_number_2"
                                    android:layout_marginBottom="8dp"/>

                                <EditText
                                    android:id="@+id/phoneNumber2"
                                    android:layout_width="match_parent"
                                    android:layout_height="55dp"
                                    android:layout_marginBottom="16dp"
                                    android:inputType="phone"
                                    android:imeOptions="actionNext"
                                    android:addTextChangedListener="@{outlet.onOtherPhoneNumberChanged}"
                                    android:text="@{outlet.phoneNumber}"
                                    android:singleLine="true"
                                    android:nextFocusDown="@+id/outletOwnerEmail"/>

                            </LinearLayout>

                        </LinearLayout>

                    </LinearLayout>

                </android.support.v7.widget.CardView>

            </LinearLayout>

        </android.support.v4.widget.NestedScrollView>
    </layout>

And my Observable Object is this

    public class Outlet extends BaseObservable {

        private static final String TAG = "Outlet";
        @SerializedName("name")
        @Expose
        private String name;
        @SerializedName("firstName")
        @Expose
        private String firstName;
        @SerializedName("lastName")
        @Expose
        private String lastName;
        @SerializedName("phoneNumber")
        @Expose
        private String phoneNumber;
        @SerializedName("otherNumber")
        @Expose
        private String otherNumber;
        @SerializedName("address")
        @Expose
        private String address;

        /**
         * 
         * @return
         *     The name
         */
        @Bindable
        public String getName() {
            return name;
        }

        /**
         * 
         * @param name
         *     The name
         */
        public void setName(String name) {
            setAtomicName(name);
            notifyPropertyChanged(BR.name);
        }

        public void setAtomicName(String basic) {
            this.name = basic;
        }

        public TextWatcher onNameChanged = new SimpleTextWatcher() {
            @Override
            public void onTextChanged(String newValue) {
                Log.e(TAG+"Name", newValue);
                setAtomicName(newValue);
            }
        };

        /**
         * 
         * @return
         *     The firstName
         */
        @Bindable
        public String getFirstName() {
            return firstName;
        }

        /**
         * 
         * @param firstName
         *     The firstName
         */
        public void setFirstName(String firstName) {
            setAtomicFirstName(firstName);
            notifyPropertyChanged(BR.firstName);
        }

        public void setAtomicFirstName(String basic) {
            this.firstName = basic;
        }

        public TextWatcher onFirstNameChanged = new SimpleTextWatcher() {
            @Override
            public void onTextChanged(String newValue) {
                Log.e(TAG+"FirstName", newValue);
                setAtomicFirstName(newValue);
            }
        };

        /**
         * 
         * @return
         *     The lastName
         */
        @Bindable
        public String getLastName() {
            return lastName;
        }

        /**
         * 
         * @param lastName
         *     The lastName
         */
        public void setLastName(String lastName) {
            setAtomicLastName(lastName);
            notifyPropertyChanged(BR.lastName);
        }

        public void setAtomicLastName(String basic) {
            this.lastName = basic;
        }

        public TextWatcher onLastNameChanged = new SimpleTextWatcher() {
            @Override
            public void onTextChanged(String newValue) {
                Log.e(TAG+"lstname", newValue);
                setAtomicLastName(newValue);
            }
        };

        /**
         * 
         * @return
         *     The phoneNumber
         */
        @Bindable
        public String getPhoneNumber() {
            return phoneNumber;
        }

        /**
         * 
         * @param phoneNumber
         *     The phoneNumber
         */
        public void setPhoneNumber(String phoneNumber) {
            setAtomicPhoneNumber(phoneNumber);
            notifyPropertyChanged(BR.phoneNumber);
        }

        public void setAtomicPhoneNumber(String basic) {
            this.phoneNumber = basic;
        }

        public TextWatcher onPhoneNumberChanged = new SimpleTextWatcher() {
            @Override
            public void onTextChanged(String newValue) {
                Log.e(TAG+"phonenumber", newValue);
                setAtomicPhoneNumber(newValue);
            }
        };

        /**
         *
         * @return
         *     The otherNumber
         */
        public String getOtherNumber() {
            return otherNumber;
        }

        /**
         *
         * @param otherNumber
         *     The otherNumber
         */
        public void setOtherNumber(String otherNumber) {
            setAtomicOtherPhoneNumber(otherNumber);
            notifyPropertyChanged(BR.phoneNumber);
        }

        public void setAtomicOtherPhoneNumber(String basic) {
            this.otherNumber = basic;
        }

        public TextWatcher onOtherPhoneNumberChanged = new SimpleTextWatcher() {
            @Override
            public void onTextChanged(String newValue) {
                Log.e(TAG+"otherphone", newValue);
                setAtomicOtherPhoneNumber(newValue);
            }
        };

        /**
         * 
         * @return
         *     The address
         */
        @Bindable
        public String getAddress() {
            return address;
        }

        /**
         * 
         * @param address
         *     The address
         */
        public void setAddress(String address) {
            setAtomicAddress(address);
            notifyPropertyChanged(BR.phoneNumber);
        }

        public void setAtomicAddress(String basic) {
            this.address = basic;
        }

        public TextWatcher onAddresChanged = new SimpleTextWatcher() {
            @Override
            public void onTextChanged(String newValue) {
                Log.e(TAG+"address", newValue);
                setAtomicAddress(newValue);
            }
        };

        @BindingAdapter({"bind:email"})
        public static void checkEmail(EditText editText, String email) {
            if (editText != null) {
                editText.addTextChangedListener(new TextWatcher() {
                    @Override
                    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                    }

                    @Override
                    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                    }

                    @Override
                    public void afterTextChanged(Editable editable) {
                        if (editText.length() > 0) {
                            if (!Utils.emailMatchPattern(editText.getText().toString())) editText.setError("Email Requried");
                        }
                    }
                });
            }
        }
    }

When I do this. Outlet outlet = new Outlet(); and assign it to my binding data like this binding.setOutlet(outlet); I wouldn't get any error. But, if I do this:

Outlet outlet = gson.fromJson(realmOutlet.getPayload(), Outlet.class);
binding.setOutlet(outlet);

I get an NPE Error and based on the NPE, it's not because the data is not there. It's like as if the adapters hasn't been initialized. I know it keeps pointing to the addressField because, it's the first item. And this is the adapter for Address. It's an abstract class. So, I'm confused why aren't they initializede:

 public TextWatcher onAddresChanged = new SimpleTextWatcher() {
            @Override
            public void onTextChanged(String newValue) {
                Log.e(TAG+"address", newValue);
                setAtomicAddress(newValue);
            }
        };

Below is my Log I can't trace the log to know what exactly to debug. But, for it to be saying the view attaching itself to the Interface method is null. It's like, the Binding Layouts has not been initialized yet. So, why is it working when I initialize it with empty data?

And my onCreate code

     @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.activity_create);
        binding = DataBindingUtil.setContentView(this, R.layout.activity_create);
        realm = RealmUtils.getRealmInstance(getApplicationContext());

        setSupportActionBar(binding.createToolbar);
        action = getIntent().getStringExtra("action");

        if (getSupportActionBar() != null) {
            getSupportActionBar().setDisplayHomeAsUpEnabled(true);
            initAutoCompletedTexts();
            if (action != null) {
                if (action.equals("create")) {
                    getSupportActionBar().setTitle(R.string.create);
                    outlet = new Outlet();
                    outlet.setShopkeeper(shopkeeper);
                    binding.setOutlet(outlet);
                } else {
                    getSupportActionBar().setTitle(R.string.update);
                    binding.saveBtn.setText("UPDATE");
                    initUpdateSpcific();

                }
            }
        }

        //createBinding.setCustomer(outlet);
        binding.saveBtn.setOnClickListener(view -> {
            save();
        });
    }
7
  • 1
    Outlet outlet = new Outlet(); is initialisation and Outlet outlet = gson.fromJson(realmOutlet.getPayload(), Outlet.class); is setting a value without initialisation. there isn't any Log attached! Commented Aug 13, 2016 at 15:10
  • Yeah. But, with pre-filled data. And attaching it to the databinder. Isn't that the essence of Databinding? Auto populating views with data and collecting data from views? @Smit Commented Aug 13, 2016 at 15:12
  • 1
    why not try this out Outlet outlet = new Outlet(); then Outlet outlet = gson.fromJson(realmOutlet.getPayload(), Outlet.class); then binding.setOutlet(outlet); how about this? And then the subsequent updates can just set the values outlet = gson.fromJson(realmOutlet.getPayload(), Outlet.class); Commented Aug 13, 2016 at 15:19
  • So, you're saying I should initialize Outlet outlet = new Outlet(); and attach it to the binder. And then collect the data. Then append the data? Commented Aug 13, 2016 at 15:24
  • 1
    sorry about the trouble, did that solve the issue? Commented Aug 13, 2016 at 15:38

1 Answer 1

1

There are few things to take note:

1) Initialisation works the following way:

Outlet outlet = new Outlet();

2) Assigning a value:

Outlet outlet = gson.fromJson(realmOutlet.getPayload(), Outlet.class);

In order to keep the databinded you MUST initialise and then update the data accordingly.

So you have to do both but in a structured way, i.e

Outlet outlet = new Outlet();
    Outlet outlet = gson.fromJson(realmOutlet.getPayload(), Outlet.class);      
    binding.setOutlet(outlet);

And the subsequent updates: assign the values and setOutlet

outlet = gson.fromJson(realmOutlet.getPayload(), Outlet.class);
    binding.setOutlet(outlet);

UPDATE:

This is just answer to you question and the followup of the chat we had in comments so that other can take reference from.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.