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.

 

Instantiate the UI Data model inside your Activity or Fragment:

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,

 

MVVM – Android’s Architecture Components Part 2 – Repository Pattern

In the Part 1 of Android Architectural Component series, we have implemented two-way data binding and explained the Android Architectural components: ViewModel and Live Data, and LifeCycleOwner. However, the data layer part of the app was not complete, more specifically we did not implement the Repository Pattern. The previous example did not have a persistence solution to cache data from API. This might be required in many use cases for following reasons:

  1. User experience: making the user wait for some data is bad user experience, when possible, it needs to be avoided
  2. Data needs to be persisted: user needs to login once
  3. Waste of network resource: re-fetch same data
  4. Data lost: Flaky network can prevent you from obtaining data anytime
  5. Android OS/GC can clear data which is store in memory anytime.

In this blog post, we will go through the detail of our open source example of the MVVM android app implementing the Architectural Components guideline. Since this guideline was released only year, I did not find many open source project which is complete. Our example follows the Android App Guideline as strictly as possible and the source code is easy to understand:

Persistence data using Room DAO & LiveData

The Android Architecture Components provides a library to persist data: Room DAO. In a previous blog post, we have discussed about how to setup the Room Persistence Library: https://devanshramen.com/2017/09/20/intro-to-room-persistence-library/. Feel free to go back to this if you haven’t used Room before.

@Dao
public interface UserDao {
    
    @Query("SELECT * FROM user LIMIT 1")
    LiveData<User> getUser();

    @Insert
    (onConflict = OnConflictStrategy.REPLACE)
    void insert(User user);

    @Delete
    void delete(User user);

    @Query("DELETE FROM user")
    void deleteAll();
}

 

  • Returning LiveData

@Query(“SELECT * FROM user LIMIT 1”)
LiveData<User> getUser();

LiveData as mentioned in Part 1 of Android Architectural Component will notify any of its observers when its value changes. For instance, in our login example, the user entity will be updated when the Login API operation is successful (user will be inserted into user entity).

 

Fetching Data from Webservice

In the blog post, we were calling Login API operation inside of our ViewModel. We marked this part TODO and rightly so. Other than not providing a Persistence solution, the ViewModel is responsible for holding Data for the Activity and Fragment. Fetching data inside the ViewModel would violate the Single Responsibility Principal. This would make our app more difficult to maintain as it is scaled when new features are added. We will have a new class “UserRepository” to manage all operations which are at the “data layer”. (Note that we are using a mock api and does not include any authentication or use of token for this example in which we won’t go through this part)

 

UserRepository

The Repository class (modules if we use dagger2), will manage data which is being cached local repository or which needs to be sent to a remote repository (through web service). The UserRepository is using Room (userDao) and Retrofit for remote data.

public class UserRepository {
    UserDao userDao;
    Executor executor;

    public UserRepository() {
        this.userDao = AppDatabase.getAppDatabase(MApplication.context).userDao();
        executor = Executors.newSingleThreadExecutor();
    }

    public void clearUserCached() {
        executor.execute(() -> {
            userDao.deleteAll();
        });
    }

    public void loginUser(String email, String password) {

        getAPIService().login(new LoginRequest(email, password))
            .compose(RxUtils.applySchedulers())
            .subscribe(
                (LoginResponse response) -> {
                    executor.execute(() -> {
                        userDao.insert(response.getUser());
                    });
                },
                (Throwable e) -> {
                    e.printStackTrace();
                }
            );
    }

    public LiveData<User> getUser() {
        return userDao.getUser();  
    }
}

  • loginUser(String email, String password): 

We have now exposed a method for network call to perform the login operation inside of the UserRepository. The key point here is that when the operation is successfully we will update the RoomDao:

executor.execute(() -> {
    userDao.insert(response.getUser());
});

(note that the i/o operation for Room needs to be done in background thread – thereby use of executor)

 

  • LiveData<User> getUser(): 

Our LoginViewModel will setup its UserResponse LiveData attribute with this method such that the LiveData for User Entity in Room DAO will be used to detect if user data was updated.

 

  • Optimise code with Dependency Injection:

Note that we can optimise this class for scalability by using Dependency Injection to provide for UserDAO with a single implementation and thereby avoid some code duplication.

 

Updated LoginViewModel

public class LoginViewModel extends ViewModel {

    // Create a LiveData
    private LiveData<User> userResponse;

    public final ObservableField<String> email = new ObservableField<>();
    public final ObservableField<String> password = new ObservableField<>();

    public final ObservableField<String> errorEmail = new ObservableField<>();
    public final ObservableField<String> errorPassword = new ObservableField<>();

    UserRepository userRepository;

    public LoginViewModel() {
        userRepository = new UserRepository();
        userResponse = userRepository.getUser();
    }

    public LiveData<User> getUser() {
        return userResponse;
    }
    
    public void onBtnLoginClick() {
        if (validateInputs()) {
            userRepository.loginUser(email.get(), password.get());
        }
    }
   .
   .
   .
}

We were previously using an observable on LoginResponse. This has been updated to use LiveData and the UserRepository which has the implementation for calling login API and which can talk to UserDao. Note that the updated ViewModel will not have any implementation for fetching cached data or data from a Web service.

  • Subscribe to UserDao from UserRepository

The method getUser() from UserRepository returns the LiveData<User> from UserDao:

public LoginViewModel() {
    userRepository = new UserRepository();
    userResponse = userRepository.getUser();  
}

 

The LoginViewModel exposes the LiveData to the LoginActivity so that the Activity can take UI actions should the data in UserDao be updated:

public LiveData<User> getUser() {
    return userResponse;
}

 

  • Calling Login method from UserRespository: 
public void onBtnLoginClick() {
    if (validateInputs()) {
        userRepository.loginUser(email.get(), password.get());
    }
}

 

LoginActivity – User Observer

The Login will remain same as before but now we will get user object instead of LoginResponse. It will also be notified in theory of changes from UserDAO instead of actual Login API.

// The observer updates the UI when UserDAO is updated
mViewModel.getUser().observe(this, userResponse -> {
    if (userResponse != null) {
        Toast.makeText(LoginActivity.this, "Login success", Toast.LENGTH_SHORT).show();

        Intent intent = new Intent(this, MainActivity.class);
        startActivity(intent);
        finish();

    } else {
        Log.d("LoginActivity", "value user is null");
        // Show ERROR
    }
});

 

MainActivity

For the sake of the example, we have added a MainActivity class which will display the user’s details. The data will be retrieved directly from Room UserDAO without requiring to make another API call to fetch data. It also shows that the data was successfully cached.

  • Display cached User Details: 
// The observer updates the UI to display prefetched user details
mViewModel.getUser().observe(this, userResponse -> {

    if (userResponse != null) {
        binding.txtWelcome.setText("Welcome " + userResponse.getFirstName() + " " + userResponse.getLastName()
                + "\n\n" + "You are more than a " + userResponse.getJobTitle());

    } else {
        logoutUser();
    }
});

 

MainViewModel

The MainViewModel will also make use of the same method (userRepository.getUser()) from UserRepository to get cached user:

public class MainViewModel extends ViewModel {
    private UserRepository userRepository;

    public MainViewModel() {
        userRepository = new UserRepository();
    }

    public LiveData<User> getUser() {
        return userRepository.getUser();
    }

    public void clearUserData() {
        userRepository.clearUserCached();
    }
}

Conclusion:

That’s it, we have now implemented the Repository Pattern and completed the Part 2 of our MVVM using new Android Architectural components. Please find the full project source below:

https://github.com/devansh-ramen/Android-App-Architecture-MVVM

Do not forget hit the “Star” button on the project repository:

If you have any queries, feel free to post a comment in the Comment section below, I will respond to you as soon as possible.

 

Sharing data between your Apps on Android using Content Provider

Hello in this blog post we are going to talk about how you can share database or files between your apps on Android. This situation can be useful if for e.g, you have Widget App and another Launcher App which need to share same database. Or you have many applications which need consume similar set of data. Another possible scenario is if you want to share some important data which resides in your application to any other apps who may need it. You may already be consuming data from other apps (e.g, from Android OS, to access contacts, media files or calendar events). For all of the above scenerios, the Android SDK came up with “ContentProvider” as a solution.

ContentProvider is appropriate when you want to share your database or flat files between Android apps. Under the hood, Content Provider will a set the implementation for performance and security optimization. On implementation level, of the ContentProvider abstract class, we will need to override required abstract methods to provide our own implementation on how to perform CRUD operation (create, read, update, delete operation) . And our ContentProvider can be consumed through ContentResolver. I will provide you the full source and in the blog post I will go through the concepts and implementations.

Creating your own Provider to share database

In our example, we have an app which wants to share an SQLite database to other apps. We will do so by creating our own Content Provider share the “Phonebook” table. The Phonebook table contains person’s name and their corresponding phone number. I will assume you already know how to setup SQLite database here.

ContentProvider – Abstract methods to be implemented

ContentProvider is an abstract class and we will be required to implement the following methods to allow other consumers to access/update our PhoneBook table:

  • OnCreate() method – Prepares the content provider

In the OnCreate method, we can create an instance of our SqliteDatabase such that other methods will get an instance of dbManager to insert/delete/update objects.

private SqliteDatabaseManager dbManager;
@Override
public boolean onCreate() {
 dbManager = new SqliteDatabaseManager(getContext());
 return false;
}
  • getType() – Returns the MIME type for this URI
  • query() method – For any Query request
public Cursor query(@NonNull Uri uri, String[] projections, String selection, String[] selectionArgs, String sortOrder) {
}
  • insert() method – inserting into the Phonebook table. ContentValues will contain the data to be inserted. E.g, person’s name and phonenumber
@Override
public Uri insert(Uri uri, ContentValues contentValues) {
}

Inside the insert method, we can insert the data into SQLite database.

  • delete() method – deleting object from Phonebook table
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
}
  • update() method – updating object from Phonebook table
@Override
public int update(Uri uri, ContentValues contentValues, String selection, String[] selectionArgs) {
}

Important methods:

URIMatcher – To deal with multiple URIs Android provides the helper class UriMatcher – https://developer.android.com/reference/android/content/UriMatcher.html

Contract Class – ContractPhonebook class

This class that we coded is also known as a contract class. A contract class explicitly specifies the schema (how a database and its tables are organized).

Exposing our ContentProvider – AndroidManifest.xml

We will need to declare “Provider” element to expose our ContentProvider inside the application tag in our AndroidManifest.xml file:

Refs: https://developer.android.com/guide/topics/manifest/provider-element.html

<permission android:name="com.devanshapps.programmingreferences.READ_DATABASE"
    android:protectionLevel="normal" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity android:name="com.devanshapps.programmingreferences.MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <provider
        android:authorities="com.devanshapps.programmingreferences.Phonebook"
        android:name="com.devanshapps.programmingreferences.PhonebookProvider"
        android:permission="com.sqisland.android.protected_provider.ACCESS_DATA"
        android:exported="true"/>
</application>

Noticed that we have created our Permission with protectionLevel = “signature”:

<permission android:name="com.devanshapps.programmingreferences.READ_DATABASE"
    android:protectionLevel="signature" />

So any other apps which want to access our ContentProvider will get this permission. With android:protectionLevel=”signature”, we will only allow applications which use the same “keystore” to be able to obtain this permission. Basically we will have this permission if we want to limit access to e.g, only our own applications signed with same Keystore.

Using ContentResolver to insert data

String AUTHORITY = "com.devanshapps.programmingreferences.Phonebook";
String PATH  = "/phonebook";
Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + PATH);
ContentValues values = new ContentValues();
values.put("person_name", "Devansh Ramen");
values.put("phone_number", "12300000");
Uri mUri = getContentResolver().insert(CONTENT_URI, values);

The ContentProvider can be accessed with any other applications such that we are able to perform CRUD operation on the PhoneBook table.

Example Source code

Please find the full source code as discussed in the blog post on . github: https://github.com/devansh-ramen/Android-ContentProvider-Example

Conclusion

I hope you have learned when you will need to use Content Provider and how to create your own content providers or consume those from other apps on android. If you have any question or helpful information, we can “share” through the Comment Section below! 😉 Please subscribe for more post. Catch you in next one!! Happy coding

Reference:

https://developer.android.com/guide/topics/providers/content-provider-creating.html

Explaining Dependency Injection with Dagger 2 – Android

Dagger 2 is a dependency injection framework.

Example of a Dependency

Below is an example where we have Class A which requires and instance of another class.

public class A {
  private B b;
  public A() {
    b = new B();
  }
}

There are a few issues with above code:

  • Class A implementation depends of constructor of Class B. E.g if constructor of class B changes, we need to update variable “b” initialization.
  • If have to use same instance of variable B in several classes, we have to duplicate same initialization code in other classes’s constructor (e.g onCreate method – Android).

The idea and aim when using dependency injection is to “decouple” implementations, making class A less dependent on Class B’s implementation. E.g if we need to change implementation of B, the implementation code for Class A will not require any change.

One way to achieve this is to declare class’s B initialization in another class so that all classes which require object will get it from there. That’s what a dependency injection framework does, but in a clean and more robust way.

Getting started with Dagger 2 on Android

On Android, as an example, we would often instance of DB manager or HttpClient inside many of our Activities/Presenter. We could use “static” methods/objects as well, but DI is the “right” way and can be more reliable. So let’s take a deeper look at how to get started with Dagger 2.

Step 1: Gradle import

First let’s add this to the app module’s gradle file:

compile 'com.google.dagger:dagger:2.10'
annotationProcessor 'com.google.dagger:dagger-compiler:2.10'
testAnnotationProcessor 'com.google.dagger:dagger-compiler:2.10'

Step 2: Create packages

I would advise to create a package named “di”. Inside of “di”, inside we will have two packages: “component” and “module”.

Example:

Screen Shot 2017-08-24 at 1.29.11 PM.png

 

Step 3: Create Module class:

Let’s create “ContextModule” class inside “di/module” package

@Module
public class ContextModule {

    private final Context context;

    public ContextModule(Context context) { // Constructor
        this.context = context;
    }

    @Singleton
    @Provides
    public Context getContext() { // Provides means Context objects to any method inside Module class or for injecting in other classes
        return context;
    }
}

Dagger 2 uses the following annotations:

  • @Module: define classes which provide dependencies
  • @Provides: define method which provide dependencies. E.g Context objects will be provided by this method.

Step 4: Building your project and Wiring up DI inside Application Class

After defining the module, you will need to build your project (may require clean as well). There will be some generated classes in our example, it will be for “ContextModule”. After building project, go to you application class, and add following:

appComponent = DaggerAppComponent.builder()
        .contextModule(new ContextModule(getApplicationContext()))
        .build();

For all modules, we create an instance by providing the constructor

Step 5: Define Component

Now we need to list of Activities/Classes which will require all dependencies we defined in our “Modules” classes (in our example, we have only “Application Context”).

@Singleton @Component(modules = {ContextModule.class,NetworkModule.class,DatabaseModule.class}) public interface AppComponent { void inject(BaseFragment fragment); void inject(BasePresenter presenter); void inject(BaseActivity activity); } What I do, I will have Base Classes for my Activities/Fragments/Presenter, e.g “BaseActivity” where we will need to do an additional wiring so that objects can be injected on e.g any Activities which extend BaseActivity.

Step 6: Wiring on Base Activities/Fragments/Presenters

public class BasePresenter implements BaseContract.BasePresenter {

    @Nonnull
    BaseContract.AppBaseView mView;

    @Inject
    protected Context context; // We are injecting the context provided from Application Class

    public BasePresenter(@Nonnull BaseContract.AppBaseView mView) {
        this.mView = mView;

        MApplication.getAppComponent().inject(this); // Wiring dependencies so that we can inject objects from Module class

        mSubscription = new CompositeSubscription();

        LogUtils.showLogDebug("subscribe");
    }
   .
   .
   .

-> MApplication.getAppComponent().inject(this);

This is how we wire the BasePresenter to Dagger so that we can inject all dependencies define in our module classes.

If you used “ButterKnife” library for injecting layout elements into Activities/Fragments classes, you know you have to call “ButterKnife.bind(this)” after Activity is created. ButterKnife also uses DI for injecting the layout items into related java/activity class.

That’s it. Now for any classes which extend the BasePresenter, you will be able to inject all dependencies defined.

Below is another example for BaseActivity

public abstract class BaseActivity extends AppCompatActivity implements BaseContract.BaseView {

    @Nonnull
    MgProgressBasePresenter mPresenter; 
    
    @Inject
    protected Context context; // We are injecting the context provided from Application Class

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getResourceLayout());
        ButterKnife.bind(this);

        MApplication.getAppComponent().inject(this); // "Binding" dagger dependency

        onViewReady(savedInstanceState);
        mPresenter = new BasePresenter(this);
    }

Too much boilerplate?

We were injecting only the Context class which might not seem very useful, but imagine if you had a Database Module, a Network module, and these constructors will be defined in only one place.

You can have a look at the Network Module for example:

@Module
public class NetworkModule {

    private String baseUrl;

    public NetworkModule(String baseUrl) {
        this.baseUrl = baseUrl;
    }

    @Singleton
    @Provides
    public OkHttpClient.Builder getHttpClient() {
        return new OkHttpClient.Builder();
    }

    @Singleton
    @Provides
    public Retrofit.Builder getRetrofitBuilder() {
        return new Retrofit.Builder();
    }

    @Singleton
    @Provides
    public APIService getService(Context context, OkHttpClient.Builder httpClient, Retrofit.Builder retrofit) {
        .
        .
        .
    }

Please note here, we have getHttpClient() method, and getRetrofitBuilder() method which provides instances of OkHttpClient.Builder and Retrofit.Builder retrofit which will provide for instances for required arguments inside “getService(…)” method within the Module. So we are defining how the arguments inside getService will get it’s instances. Same apply for Context which shall be obtained from the ContextModule.

So now on our presenters (or fragments), we can inject another object without requiring any additional “wiring up” on our classes:

@Inject
APIService apiService;

I guess that’s all for today. Let me know if there is anything missing or any issue which you are getting with using Dagger 2 on Android. Catch you soon with another post.

Cheers,