Build It Bigger - 1/2

For my first blog post, I propose the description step by step of my solution for the exercise Udacity - Build it bigger.

To better understand this exercise, some useful links:

Actually, I work on my capstone project. But when I have make this exercise, I already think to write this blog post. With this perspective, I have voluntary make the smallest commit as possible to provide something readable. You can see the solution without read this post, simply follow the commit step by step here

For those who want more details than only code, let’s start!

What we search to do

This exercise is focus on interactions between libraries/modules and your app. This exercise is focused primarily on the outright application of lessons offered in “Gradle for Android and Java”.

If we atomize the final expected solution, we obtain:

  • A Java library that provides jokes
  • A Google Cloud Endpoints (GCE) project that serves those jokes
  • An Android app who make the gap between the GCE module and the Android Library
  • An Android Library containing an activity for displaying

The supplied diagram illustrates very well the interactions between elements:

Build It Bigger

Create a Java library that provides jokes (commit)

Review the associated video lesson

After fork or copy-paste of the starting point, we should begin by create the java library.

Use the Wizard of Android Studio :

  • In Android Studio: File > New Module…
  • Choose “Java Library”
  • Library name: jokelib
  • Java Class name: JokeProvider

Tips: When you use the wizard, files are created by gradle. If you want lost a lot of times with incomprehensible problems, open and modify files recently create before the end of gradle tasks.

The wizard do it for us. But it is useful to know that it was added to settings.gradle:

settings.gradle

Add this source compatibility in the new module:

jokelib/build.gradle

Create a static final array of Strings to stock the jokes. Here, the getJoke method choose randomly the joke to return.

jokelib/src/main/java/com/joke/JokeProvider.java

And that’s all! Seriously, the hardest point, it’s to find good jokes!

Make the button display a toast showing a joke (commit)

We have good jokes, now we want to see them!

For this, import the new java library jokelib in the main project:

app/build.gradle

In the MainActivity, replace the Toast with a static message by a Toast who call the static method getJoke of JokeProvider class. I have increased the display time of Toast in order to have time to read the joke.

app/src/main/java/com/udacity/gradle/builditbigger/MainActivity.java

You can already build, run, click on the button, and laugh! Isn’t it wonderful?

Create a new empty Activity library/module (commit)

Review the associated video lesson

View a joke in a toast isn’t ideal, we would display it in a new Activity to have time to enjoy. But we want to reuse this Activity in another project, so we need to put it in an android library.

Create a new empty android library with the wizard:

  • In Android Studio: File > New Module…
  • Choose “Android Library”
  • Application/Library name: JokeActivity
  • Module name: jokedisplay

Tips: If you are in a hurry, wait… (the end of gradle tasks)

Like before, the wizard do it for us. But it is useful to know that it was added to settings.gradle:

settings.gradle

Display a joke passed to it as an intent extra (commit)

My wizard do strange things. To ensure that you do not have the same problem as me, check the module created is a library not an application:

jokedisplay/build.gradle

Check if you have an appliId in your android library. In this case, delete it:

jokedisplay/build.gradle

And now, you have two manifests in your project. Change allowBackup="false" to avoid conflict.

jokedisplay/src/main/AndroidManifest.xml

Import the new module android library in the main application:

app/build.gradle

In the android library jokedisplay, catch the bundle of intent, and extract the joke to set a textview:

jokedisplay/src/main/java/com/joke/JokeActivity.java

In the main app, replace the toast by an explicit intent. And put the joke in extras of intent:

app/src/main/java/com/udacity/gradle/builditbigger/MainActivity.java

Replace the method called when the button is clicked:

app/src/main/res/layout/fragment_main.xml

We took the opportunity to add a default text if no joke has been extracted from the intent:

jokedisplay/src/main/res/layout/activity_joke.xml
jokedisplay/src/main/res/values/strings.xml

Create a new empty Google Cloud Endpoint (commit)

Now, we want to put in the cloud the java library who provide the jokes. We need to create a Google Cloud Endpoint who do the gap between the java library and the main application.

To begin, create a new Google Cloud Endpoint with the wizard:

  • In Android Studio: File > New Module…
  • Choose “Google Cloud Module”
  • Module type: App Engine Java Endpoints Module
  • Module name: backend
  • Package Name: com.joke.endpoint.backend
  • Client Module: app(com.udacity.gradle.builditbigger)

Tips: Wait… (take the opportunity to comment)

Like before, the wizard do it for us:

settings.gradle

And the wizard do this too:

app/build.gradle

Modify the GCE starter code to pull jokes from Java library (commit)

Import the java library module jokelib in the Google Cloud Endpoint module backend:

backend/build.gradle

Modify the GCE to provide joke from JokeProviderclass:

backend/src/main/java/com/joke/endpoint/backend/MyEndpoint.java

Connect Android app to the backend

Emulator with local dev server (commit)

Now, it’s GCE who provide joke, the java library doesn’t need to be connected directly to the main application. Delete the import of libjoke in the main application:

app/build.gradle

Create and configure the EndpointAsyncTask to test on emulator with local dev server:

app/src/main/java/com/udacity/gradle/builditbigger/EndpointsAsyncTask.java

In the main application, replace the intent by a call to EndpointsAsyncTask:

app/src/main/java/com/udacity/gradle/builditbigger/MainActivity.java

You can test this configuration launching a local dev server for the GCE, and running the main app on emulator!

Real device with local dev server (commit)

Get your IP address on your computer, go to cmd -> ipconfig -> IPV4 address with port number and modify the API Builder:

app/src/main/java/com/udacity/gradle/builditbigger/EndpointsAsyncTask.java

Set the httpAddress in build.gradle:

backend/build.gradle

You can test this configuration launching a local dev server for the GCE, and running the main app on a real device!

Real device with backend deploy to App Engine (commit)

Get your real url of backend deployed and modify the API Builder:

app/src/main/java/com/udacity/gradle/builditbigger/EndpointsAsyncTask.java

Don’t forget to delete this:

backend/build.gradle

You can test this configuration deploying backend to App Engine, and running the main app on a real device!

Add functional test to check Async task successfully retrieves a non-empty string (commit)

Set AndroidJUnitRunner as the default test instrumentation runner:

app/build.gradle

Add this for Testing Support Library:

app/build.gradle

Create test who check the returned string is not null and not empty:

app/src/androidTest/java/com/udacity/gradle/builditbigger/EndpointsAsyncTaskTest.java