Two-Way Data binding in Android

Two-way data binding is a way to update your Views attributes using Observable objects and vice-versa. In Android framework you would essentially define an observable object which would notify your views (e.g EditTexts) whenever it is updated. The term “Two-way” means that whenever your views are updated, your observable object would also get updated. This design pattern allows for loose coupling between your Android layout and your Activities/Fragments. It is often used in MVVM pattern.

Without further due, let’s develop our data binding app. By default, data binding is not enabled in a new project. Let’s start with enabling data binding:

Update build.gradle for app module (Module: app)

Inside of “android {} ” tag add the code:

dataBinding {
    enabled = true
}

 

The result build.gradle (Module: app) should be as below  :

android {
    compileSdkVersion 27
    defaultConfig {
        applicationId "devanshapps.databindingexampleapp"
        minSdkVersion 17
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    dataBinding {
        enabled = true
    }
}

Note enabling data binding will actually import the android.databinding support library 

 

Our App Design

For this example, we will have a simple design with a list of EditText inputs as below:

Screen Shot 2018-10-06 at 8.49.05 PM.png

 

Enabling Data Binding in a layout file

To enable data binding you would need to update your root/parent view to “layout” tag:

<?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"
    xmlns:tools="http://schemas.android.com/tools">

    <android.support.constraint.ConstraintLayout 
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <EditText
            android:id="@+id/edt_firstname"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginEnd="8dp"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:ems="10"
            android:inputType="textPersonName"
            android:text="First Name"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

         .
         .
         .
    </android.support.constraint.ConstraintLayout>
</layout>

 

Accessing views from Java

You will first need to “Build” your project so that the required “data binding” classes get generated. In our case, since our layout file name is “activity_main.xml”, the class ActivityMainBinding will get generated.

In our MainActivity.class, you will need to replace “setContent(R.layout.activity_main);” with the generated ActivityMainBinding. The result will be as below:

public class MainActivity extends AppCompatActivity {
    ActivityMainBinding binding;

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

        setContentView(R.layout.activity_main);
        binding = 
          DataBindingUtil.setContentView(this, R.layout.activity_main);
    }
}

If all is setup properly, you should be able to access EditTexts defined from “binding” object itself as below:

private void setViews() {
    binding.edtFirstname.setText("Bob");
    binding.edtSurname.setText("Dylan");
}

Note: We are not there yet with regards to our actual two-way data binding!

 

Create an Observable class for UI data fields:

Our observable object needs to extend “BaseObservable” from data binding library “android.databinding.BaseObservable

First we will add all of the required fields in our layout file:

public class User extends BaseObservable {
    private String firstName;
    private String surname;
    private String jobTitle;
    private String hobbits;
}

 

Add a reference to the User data object in the layout file:

In our activity_main.xml we will now need to add a reference to the User class as below:

<?xml version="1.0" encoding="utf-8"?>
<layout>
    <data>
        <variable
            name="data"
            type="devanshapps.databindingexampleapp.User"/>
    </data>
    
    <android.support.constraint.ConstraintLayout
    .
    .
</layout>

 

We will also need to add a reference to the attributes e.g firstName, surname, jobTitle, hobbits:

<EditText
    android:id="@+id/edt_firstname"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginEnd="8dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="8dp"
    android:ems="10"
    android:inputType="textPersonName"
    android:text="@={data.firstName}"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<EditText
    android:id="@+id/edt_surname"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginEnd="8dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="12dp"
    android:ems="10"
    android:inputType="textPersonName"
    android:text="@={data.surname}"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.0"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/edt_firstname" />

<EditText
    android:id="@+id/edt_job_title"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginEnd="8dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="16dp"
    android:ems="10"
    android:inputType="textPersonName"
    android:text="@={data.jobTitle}"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.0"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/edt_surname" />

<EditText
    android:id="@+id/edt_hobbits"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginEnd="8dp"
    android:layout_marginStart="8dp"
    android:layout_marginTop="12dp"
    android:ems="10"
    android:inputType="textPersonName"
    android:text="@={data.hobbits}"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.0"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/edt_job_title" />

 

Getters and Setters for data binding object

Note that we want to have two observers in our case; our User object observing the Views (activity_main.xml) and the Views observing the User object in java.

We will need to add the annotation “@Bindable” to the “Getter” method which is from the data binding library (“android.databinding.Bindable”). This will allow our layout file to get the value of the property  by using the getter methods.

After adding the “@Bindable” annotation to all of the fields’ Getters, build the project. This will generate BR.firstName, BR.surname, BR.jobTitle, BR.hobbits).

Call the method notifyPropertyChanged(BR.field_name) inside of the setter methods so that the views are now notified whenever a field in the user object updated. The resulting user class will look like below:

public class User extends BaseObservable {
    private String firstName = "";
    private String surname = "";
    private String jobTitle = "";
    private String hobbits = "";

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

    public void setFirstName(String firstName) {
        this.firstName = firstName;
        notifyPropertyChanged(BR.firstName);
    }

    @Bindable
    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        this.surname = surname;
        notifyPropertyChanged(BR.surname);
    }

    @Bindable
    public String getJobTitle() {
        return jobTitle;
    }

    public void setJobTitle(String jobTitle) {
        this.jobTitle = jobTitle;
        notifyPropertyChanged(BR.jobTitle);
    }

    @Bindable
    public String getHobbits() {
        return hobbits;
    }

    public void setHobbits(String hobbits) {
        this.hobbits = hobbits;
        notifyPropertyChanged(BR.hobbits);
    }
}

Cool. We are almost done. Note that we have to add the “@Bindable” annotation to the Getter method first so that the associated “BR” fields are generated.

 

Insert the User Model inside of Activity (or fragment) class:

Inside of our MainActivity, we will instantiate the User object and pass it on the the DataBinding (binding) object:

public class MainActivity extends AppCompatActivity {
    ActivityMainBinding binding;
    User data = new User();

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

        binding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        binding.setData(data);
    }
}

 

Done!

You should  now able to reflect any changes from the the User object to the Views and any user inputs to reflect into the User Object (UI model). This allows our Activity (or Fragment) to manage view data directly from the UI object with little coupling with the View (layout file). For instance, the MainActivity does not need to know if “firstName” is an EditText or a TextView (type of view), changing the EditText to TextView will not require any change inside of MainActivity or User Object Model.

I have added the following code in the example project to showcase the two-way data binding in action:

private void setViews() {
    data.setFirstName("Bob");
    data.setSurname("Dylan");
}

public void printData(View view) {  // onclick on "Print" button listener
    Log.i(MainActivity.class.toString(),
            "User data: "  + data.getFirstName() + " " + data.getSurname()
                    + " works as " + data.getJobTitle() + " and likes to " + data.getHobbits());

}

 

Basically the Activity will load with the fields “first name” and “surname” set to “Bob” and “Dylan”. Also I have added button “Print” which will get updated values of EditTexts from the User object after the user has changed fields values. The complete source code for the example project is available on github: https://github.com/devansh-ramen/Two-Way-DataBinding-Android

That will be it for this post on “Two-way” data binding. There are few additional tweaks which may be are required for e.g, to use “Spinner” views or to add String Utils method (e.g formatting values) displayed in views. But this might be a good topic for another blog post. We have covered the basic to get started and running with the two-way data binding. This should already help to make our code cleaner and faster to debug/develop. As always happy coding. You can always let me know if you are getting stuck in some related issues.

Cheers.

Regards,

 

Review ‘Strapi’ as CMS/API solution for mobile apps

If you need a quick and easy solution for your backend APIs + a CMS, I would recommend you to have a look at Strapi.io. The solution near zero coding to get started.

The project comes by default with APIs for Login, forget password, Registration, Login via Social Medias. All the APIs are secured OAuth. Another great feature is that you can create your schemas which can include relationships, and media type from the Admin portal itself (from web interface).  Based on the defined schemas, Strapi will automatically generate APIs to:

  1. Get a list of all objects from any schema (including nested objects/relationships)
  2. Search for one object based on its ID
  3. Count the number in any schema/table
  4. Create a new object for any schema
  5. Updated a record
  6. Delete a record

 

The CMS generated has a clean design, very easy to use on Desktop. Of course you can modify or add any APIs or the CMS interface. The generated APIs using NodeJS and the CMS uses React.JS. All React codes for the CMS web interface is store inside of “admin” folder while all of the APIs generated is stored inside of api folder.

 

There are a few downside:

Strapi is still in Alpha stage; some features may not work properly. I recently found out that fields of type images of child objects are not properly populated from APIs. However I found solution from their github which required a few modification in generated codes.

Strapi CMS is not responsive for mobile and is pretty much limited for Desktop only.

 

For more details, checkout Strapi official website: https://strapi.io

 

Best Regards

Enjoy

Sharing Printer in Ubuntu

Sharing printer in a LAN (to Windows machine or virtualbox) from a Ubuntu host machine.
1. Setup Samba:
sudo apt-get install system-config-samba.
Launch “Samba” from the launcher
Open “Preferences” > “Server Settings” and enter the work group name used in Windows.

2. Share printer:
Go to http://localhost:631/admin/ and check the box “Share printers connected to this system”.
Go to http://localhost:631/printers/ and check that the expected printer is listed.
Click the printer and check that it is listed as “Idle, Accepting Jobs, Shared, Server Default”.

3. Connect the printer:
Either:
On the Windows computer or (e.g VirtualBox), open Windows Explorer and go to the “Network” item. There’s an icon for the Ubuntu computer; open it. There’s an icon for the printer shared from Ubuntu. Right-click that one and select “Connect…”.

Or:
On the Windows computer, select “Add new printer” then “Connect to a printer on the Internet or network” and specify the full path of “http://{computername}:631/printers/{printername}”

postgresql “New Server Registration” connection problem on ubuntu?

“connection error” or “authentication problem” when trying to register a new server in pgAdmin III?

(ubuntu or xubuntu)

This post shows how to obtain & setup the “Host”, “Port”, “Username”, and “Password” of postgresql.

1) Obtain default port.  To do that, open up /etc/postgresql/x.xversion/main/postgresql.conf

See “port= 5432”. You may change the port used by postgresql.

postgresblog

2) Obtain Host.

Search the listen_addresses. For instance, here 'localhost' is my defaut host. You may alter the host here.

3) Change password.

Open terminal.

———————————————–

~$: psql -d postgres -U postgres

psql (9.1.3) Type "help" for help.
postgres=# alter user postgres with password 'mynewpassword'; ALTER ROLE
postgres=# q
~$:sudo /etc/init.d/postgresql restart
———————————————————-
Now you can run pgAdminIII. On form New Server Registration, set ‘Username’ to “postgres”, type in password you entered before, and the field ‘Name’ is up to your choice.