Showing posts with label Android. Show all posts
Showing posts with label Android. Show all posts

Realm Migrations Supercharged with Dagger





My current tech obsessions are: Realm, Dagger and Unit Testing. Therefore, I'm always looking for opportunities to improve my code in some way that involves one or more of the above. That being said, I realized that the recommended way of handling migrations in Realm could be improved significantly by means of Dagger 2. 

We're going to be refactoring the following Migration class:



With only two version updates, we already have a decent sized method to deal with. What's more if you didn't start out by creating tests for your migrations, once this method gets much longer you probably never will. But all is not lost, Dagger's Multibinding Support is coming to the rescue. Let's take a look!


Getting Setup


The first thing we're going to do is create a new Interface, VersionMigration. This will have only the following:

The migrate method will take in a DynamicRealm instance and a long which represents the previous version of the schema that you want to migrate from. 

With this available, we can now create two VersionMigration classes that implement our new Interface. Here's the implementation for the Version1Migration class:


On line 12, we implement the migrate method. Notice that we've mostly just pasted in the same code that we had in our original Migration class. The key difference is on line 16, where we use the getObjectSchema method to retrieve the schema instead of grabbing it directly. I'll explain why we did it this way momentarily.

Next we are going to create a new Dagger module, named MigrationsModule. Then by means of the following annotations: @Provides, @IntoMap, and @IntKey I'm defining how I want my VersionMigrations to be created and injected. The combination of these annotations allows all of the VersionMigration Providers to be injected into a Map. The key to the map will be an Integer that corresponds to the previous schema version that the given VersionMigration should be used for.


For example, if my previous schema version is 2 and the current schema version is 3, then I would use the Version2Migration class. There would be no need for me to use any other VersionMigration. However, if my previous schema version is 1 and the current schema version is 3, then I would use both the Version1Migration and Version2Migration classes. This will all come together once we take a look at our updated Migration class.




Our class has now been "Daggerized"! We start out by having a Map of VersionMigration Providers injected into our constructor on line 7.  Recall that in our MigrationsModule we used those three annotations: @Provides, @IntoMap, and @IntKey. Based on that, Dagger is clever enough to gather both of our Providers together and store them in a Map that uses the Integer constant we defined as the key.


Moving down to our migrate method. There on line 15 we have a simple for loop that starts with the oldVersion and goes until we get to the newVersion. Keep in mind, that the oldVersion corresponds to the schema version that is active on the user's device. It's the version that we want to migrate from, so that we can be on the newVersion. The main Dagger awesomeness happens on lines 17 - 22. We look in our versionsMigrations Map for the correct Provider using the loop variable value. Then we return an instance of the appropriate VersionMigration and execute it's migrate method. That's it. This means that no matter how many migrations we need in the future we don't have to bother this class anymore.

What's more we also have our migration logic isolated into testable bits. Here's a look at some unit tests for the Version1Migration class using JUnit and Mockito.




Remember I said, I would explain the use of the getObjectSchema method. Well, there on line 17 when I create my migration object, I override the getObjectSchema method to return a mock of the RealmObjectSchema class. I ran into several weird exceptions when I tried to mock the RealmSchema class directly, but this solution worked just fine.

I hope you can use a similar approach to make your code more testable. All of the code snippets can be found in this gist. Thanks for reading!

If you would like to view additional Android content, I encourage you to check out my video tutorials available on Caster.io.

Background Work with Android Job and Dagger




Background work on Android can be challenging when you have to support a wide range of API levels. Specifically you can use Alarm Manager, Job Scheduler or GCM Network Manager depending on your minimum API level and if the device has Play Services. To help abstract away which implementation you're using to perform background work, the good folks at Evernote have open-sourced, Android Job.

Android Job works by first allowing you to define how you want your jobs to be created, by means of the Job Creator class. Then you can schedule requests using the Job Manager and have the confidence that they will be run when the requirements are met. In the image below you can see a representation of the various components involved with using Android Job in your application. Each Job is identified by a tag; this is just a simple String that is used to differentiate the various jobs in your application.




Let's take a look at each piece!


Getting Setup


In order to use Android Job you just need to add the dependency to your build.gradle file. If you plan on taking advantage of GCM Network Manager for older devices, you will need to include that dependency as well.



Next, you would want to create your application's Job Creator. This class is responsible for providing the correct Job class that corresponds to the tag it receives in its create() method. The Job Creator is a Singleton that uses Dagger's Multibinding Support to house a Map that references Providers of Jobs. This allows you to add new Jobs to your application without having to modify the Creator class. Then on lines 15 and 16, you look in the Map for the correct Provider and return an instance of the appropriate Job.



I like to keep the definition of my Jobs in a separate Dagger module, named JobsModule. This helps to isolate those dependencies. Notice that I'm first defining my Job Manager which uses the Job Creator that we defined previously. Then by means of the following annotations: @Provides, @IntoMap, and @StringKey I'm defining how I want my Job to be created and injected. The combination of these annotations allows all of the Job Providers to be injected into the Map, with their associated tags, for later use when a Job Request is received.



Creating a Job


The heavy lifting is done by each Job class in its onRunJob() method. A simple example is queuing a Job that adds a new record to an API endpoint. Let's assume you're using Retrofit for your API needs. In the constructor of your Job you would annotate it with the @Inject annotation to get the needed dependencies, namely your API resource. Then you would perform the network operation inside of the onRunJob() method as usual. What's unique is that you should return a Result from your method, so that the system knows whether to attempt to run your Job again at a later time.




Scheduling a Request


The final piece of the puzzle is building and then scheduling your requests. In order to send a request, you would simply use the schedule() method of the Job Manager class. This method takes a Job Request as its input.



The Job Request is built inside the containing Job class. You can send information regarding the desired network connections, device state, as well as extra data to be used when the request is executed. The below is a typical request that I use when scheduling jobs in my application.



I've really enjoyed working with this library and once all the pieces are set up it's been easy to use. All the code snippets can be found in this gist. Thanks for reading!

If you would like to view some of my video content, I encourage you to check out my video course and bite-sized tutorials available on Caster.io.

Talk: Developing Apps for Emerging Markets


At Off Grid Electric our mission is to power homes across rural Africa with affordable, solar energy. In order to do that we need to provide our employees with tools that work both on and offline. So how did we do it? In this talk, learn about the techniques we employed to provide a unique online-offline experience in our Android applications.

Talk: Develop Maintainable Apps


Great Android apps only include what's needed to achieve the goals of the product, not enhance the resume of the developer. What’s more, the more maintainable an application is, the more likely it will have increased user satisfaction and decreased time to market.

Talk: Gradle Plugin Goodness


If you find yourself copying and pasting code from your application's build.gradle file every time you start a new project, then it's time you learn about creating Gradle plugins. In this presentation you will learn what it takes to create a custom Gradle plugin for use in your Android/Java applications.

Talk: From Grails to Android


One of the key new features of Grails 3 is the use of Gradle for its build system. The Android Framework also uses the Gradle build system to build, test, run and package applications. In this talk, learn how to move from developing applications for Grails 3 to Android.

Google I/O 2016 Recap



This was my second time attending Google I/O and it was once again a great experience. I put together a few highlights of the event below:

Talk: Screen Robots UI Testing with Espresso



Often when writing tests with Espresso you find a lot of onView, withId, perform calls scattered throughout your test methods. This takes away from the simplicity of the test, tends to be verbose and also litters resource ids everywhere. There's got to be a better way, right? Yes, there is...Screen Robots. In this presentation you will learn how to take advantage of the Screen Robot abstraction technique.

Testing Tricks #5 - Using Screen Robots with Espresso



In this presentation by a developer at Square: "Software Quality/Automation Testing", he discussed how they take advantage of Robots to make it easier to update tests whenever UI elements change, as well as a few additional benefits. This is a very useful abstraction technique for when you're writing large numbers of tests in Espresso. So let's look at an example of using a Screen Robot to test a simple login flow.


Before Using a Screen Robot



So the above code is how you would typically make use of Espresso, where you have multiple calls to onView() and reference the resource ids directly in each test. Two main drawbacks of this approach is that 1) if you need to change the ids in the future you have to update multiple tests, and 2) it's not very clear from first glance what you're attempting to accomplish in a given test due to the Espresso calls. So now let's look at the same example, this time using Screen Robots.


After Using a Screen Robot



Notice how the test method is more succinct and more easily conveys what we are trying to do, namely login with a given username and password and then make sure that it was a success. 

Here's the code for our LoginScreenRobot:


This allows us to have a thin abstraction layer over the Espresso calls by extending our base ScreenRobot class. Hope you found this short testing tip helpful!

Fragmented Podcast Chat

I was recently a guest on one of my favorite podcasts, Fragmented. It's a podcast that focuses on tips and tricks for improving the Android Development experience. 

We talked all about Gradle, the build system that is used for running, testing, and packaging Android applications. I wanted to share some of the highlights.

Talk: Gradle Plugin Goodness



If you find yourself copying and pasting code from your application's build.gradle file every time you start a new project, then it's time you learn about creating Gradle plugins. In this presentation you will learn what it takes to create a custom Gradle plugin for use in your Android/Java applications. 

It covers: Plugin Structure, Key Plugin Components, Testing, and Publishing


Materials


If you would like to learn more about creating high quality Android applications, I encourage you to check out my video course. Also, follow me on Twitter for my latest updates.

My 2015


Looking back on 2015, I'd have to say it was my year of "breaking free". I finally started to do many of things that I had been only dreaming of for the past several years in my career as a Software Developer. Instead of feeling like I still didn't know enough, I embraced what I did know and used that to increase my visibility in the Android Community. So here's a recap of some of the highlights.

Testing Tricks #3: Third Party APIs



When you're writing unit tests for your Android applications, you will often need to handle interactions with third party APIs. In the above image we're using the Picasso Image Loading library in our classes. Picasso has a very clean API, so it's relatively simple to work with; but with other libraries you may not be so fortunate. So what can we do to simplify our interactions with those APIs and also set ourselves up for more maintainable code in the future?

Testing Tricks #2: Finding UI Views

When you're writing Espresso tests for your Android applications, you will often need to reference the resource id of a particular view in order to make your assertions. Instead of digging through code you can take advantage of the UIAutomatorViewer tool. It's very simple to use and helps you to visualize the hierarchy of the views in your application. 

Learning RxJava for Android Devs

One of my goals this year was to learn RxJava. Similar to my goal of going to the gym, I procrastinated a bit.
However, I have recently been digging deep into RxJava, especially as it's used in Android applications. Figured I'd share some of the resources I've come upon to help others in their reactive journeys.


Resources:


What have you found useful? Share in the comments. Thanks!

Testing Tricks #1: Dealing with "new"

As I continue my efforts to get my Android applications under unit and integration tests, I have come across a few tips/tricks to successfully deal with troublesome code. So I decided to start a new blog post series, "Testing Tricks". I will try to post a new trick each week. So let's get started...


Problem Code

So I wanted to test this code:

public void readDeepLink(String path) {
    new DeepLinkReader().readDeepLink(path);
}

Just wanted to make sure the readDeepLink method was being called. The troublesome part is that I didn't want to create a actual DeepLinkReader because the real readDeepLink method made calls to the network. So what's the fix?


Solution


Wrap the call to the "new" creation in a separate method. That way I could override the newly created method with a mock. This would avoid creating a real DeepLinkReader object and would allow me to use Mockito to verify the mock's interactions.

Fixed Code


// in the MainPresenter.java
public void readDeepLink(String path) {
    getDeepLinkReader().readDeepLink(path);
}

DeepLinkReader getDeepLinkReader() {
    return new DeepLinkReader(currentData, events);
}

// in the MainPresenterTest.java
@Mock private DeepLinkReader deepLinkReader;

@Test
public void shouldReadDeepLink() throws Exception {
    MainPresenter mainPresenter = new MainPresenter() {

        DeepLinkReader getDeepLinkReader() {
            return deepLinkReader;
        }
    };

    mainPresenter.readDeepLink("washingtonpost.com");

    verify(deepLinkReader).readDeepLink("washingtonpost.com");
}
Hope you found this useful, until next time!

Conference: Android Summit 2015


This is how Android Summit started for me! A delightful dinner for the speakers where I had the chance to make some new friends; including the friendly conference committee lead by folks at Capital One.

Talk: Developing Maintainable Apps

Great Android apps only include what's needed to achieve the goals of the product, not enhance the resume of the developer. What’s more, the more maintainable an application is, the more likely it will have increased user satisfaction and decreased time to market.




So how can you do it?  Keep these four factors in mind:


  1. Choose your 3rd Party Components Wisely
  2. Keep your Code Simple
  3. Use Static Code Analysis Tools
  4. Write Unit Tests


Resources:

Testing Your Apps with AWS Device Farm


Recently, I've been on a mission to enhance the quality of the tests in the Android applications that I work on.  To that end, I was introduced to the AWS Device Farm, a cloud based app testing platform.

Android Devs Listen Up!



So listening to podcasts used to be the "thing", then it wasn't the "thing" anymore, and now it's back to being the "thing" to do.  So with that in mind I thought I'd share some of my favorite podcasts for Android developers.