The following is the first few sections of a chapter from Exploring Android, plus headings for the remaining major sections, to give you an idea about the content of the chapter.


Integrating Room Into the Repository

Having a ToDoDatabase is nice. Having our ToDoRepository use that ToDoDatabase would be even better, as then we would start saving our to-do items to a database, so they would not vanish every time our process is terminated. So, in this tutorial, we will do just that: modify ToDoRepository – and its clients — to work with ToDoDatabase.

This is a continuation of the work we did in the previous tutorial. The book’s GitHub repository contains the results of the previous tutorial as well as the results of completing the work in this tutorial.

Step #1: Getting a Database

First, we need to have our ToDoRepository get access to a ToDoDatabase.

Add this field to ToDoRepository:

  private final ToDoDatabase db;

This gives us a place to hold onto the database.

However, Android Studio got angry when you added it, pointing out that we are not initializing this final field. So, add this constructor to ToDoRepository:

  private ToDoRepository(Context ctxt) {
    db=ToDoDatabase.get(ctxt);
  }

Now, given a Context, we can get our singleton lazy-initialized instance of ToDoDatabase.

However, Android Studio got angry when you added that, because we are trying to use a zero-argument constructor in our INSTANCE field initializer. That constructor no longer exists, as we added a non-zero-argument constructor, eliminating the default zero-argument constructor. Plus, we need a Context.

So, change INSTANCE on ToDoRepository to be initialized to null:

  private static volatile ToDoRepository INSTANCE=null;

Then, we need to modify the static get() method on ToDoRepository to initialize the INSTANCE:

  public synchronized static ToDoRepository get(Context ctxt) {
    if (INSTANCE==null) {
      INSTANCE=new ToDoRepository(ctxt.getApplicationContext());
    }

    return INSTANCE;
  }

Now, we require that get() be passed a Context, so we can turn around and use that to create our ToDoRepository instance. In truth, we could skip the getApplicationContext() call here, as we know that ToDoDatabase has its own getApplicationContext() call, but it is here for safety’s sake.

Android Studio is now angry in other places in your code, as references to the old zero-parameter get() method fail.

Chief among those is Controller, which tries to initialize its toDoRepo field using that zero-parameter get() method. So, remove the field initializer, leaving you with:

  private final ToDoRepository toDoRepo;

Now Android Studio complains that we are not initializing this final field. So, add a Controller constructor to initialize it, using a passed-in Context:

  public Controller(Context ctxt) {
    toDoRepo=ToDoRepository.get(ctxt);
  }

Of course, now Android Studio will complain wherever we are using the former zero-parameter Controller constructor, as that’s now gone.

The primary use of Controller is inside the RosterViewModel constructor. Fortunately, we have access to a Context there, in the form of the Application parameter. So, modify the RosterViewModel constructor to use that Application when creating the Controller instance:

    Controller controller=new Controller(application);

At this point, the app’s main code is happy. However, our tests have lingering issues.

First, change the setUp() method on RepoTests to use ToDoRepository.get() and a Context to get the ToDoRepository instance:

@Before
public void setUp() {
  repo=ToDoRepository.get(InstrumentationRegistry.getTargetContext());
  repo.add(ToDoModel.creator()
    .description("Buy a copy of _Exploring Android_")
    .notes("See https://wares.commonsware.com")
    .isCompleted(true)
    .build());
  repo.add(ToDoModel.creator()
    .description("Complete all of the tutorials")
    .build());
  repo.add(ToDoModel.creator()
    .description("Write an app for somebody in my community")
    .notes("Talk to some people at non-profit organizations to see what they need!")
    .build());
}

InstrumentationRegistry.getTargetContext() is a wordy way of getting a Context object for the app being tested (the “target”).

Similarly, pass in InstrumentationRegistry.getTargetContext() to the Controller constructor invocation in the controller() method of ControllerTest:

    final Controller controller=new Controller(InstrumentationRegistry.getTargetContext());

At this point, the project should build and the tests should work… mainly because we are not actually using the database.

Step #2: Fixing the CRUD

The preview of this section is sleeping in.

Step #3: Fixing the Tests

The preview of this section left for Hollywood to appear in a reality TV show.

Step #4: Integrating StrictMode

The preview of this section is out seeking fame and fortune as the Dread Pirate Roberts.

What We Changed

The preview of this section was accidentally identified as an Android 'tasty treat' by the Cookie Monster.