— Project One —

Unpacking the Sandwich App Project Code

— Introduction — -

Google and Udacity teamed up to co-create a curriculum — the Grow With Google Android Developer Nanodegree — to refine intermediate Android mobile developers. The program is split into 2 terms, both 4-month periods. I was fortunate enough to be 1 of 1,000 students (of the 10,000 students from phase 1) to make it through to phase 2.

The syllabus bundles curated lessons from other courses on the platform that cover complimentary topics in more depth, like Material Design and Firebase, on top of the standard Android lessons and is segmented into subsections; each subsection hosting a set of modules that in turn host a set of quizzes and toy apps that we build along with Google and Udacity instructors.

2–3 hours per module. 3–4 toy apps per subsection. Safe to say, students prototype over 20 toy apps and build 6 portfolio pieces that undergo a rigorous review process. (This includes a two-part Capstone where we get to own a project from start to finish, wireframes to Google Play Store ready.)

Not light work, by any means at all, but rewarding, nonetheless.

Sandwich App, the first of the portfolio projects in term 2, is arguably the most straight-forward to implement. The following post is a hybrid tutorial-walk-through of my project implementation to demonstrate my thought processes at different intervals and expound upon lessons learnt along the way.

Source Code File Structure

Organizing Our Classes.

After finishing up the last video of the first section in my Udacity classroom, the time had finally come to spin up a portfolio project.

I clicked on “Instructions” expecting a long rundown of detailed steps on how to get it done, but instead, found this…

And a link to some starter code.

Where does one even start?

Clicking through to the next screen brought me to the rubric outlining all the core functionalities that our code reviewers would be grading us on. A map.

A good place to start.

The rubric started at the data source and detailed its way to the UI. I figured I’d follow suit. The data became the mission. Finding it. Parsing it. Displaying it in a sensible way.

But, where does one even find the data to get started?

I cloned the repository to my Desktop and imported the project into Android Studio (version 3.0, stable release).

When everything was booted up, I went straight to the source directory to examine the file structure:

Minimal. Taking note of the modularity, I wanted to use this project to develop an iterative workflow and a clear, mental archetype of how I should be packaging my Java classes to prep for more difficult projects down the road.

But…where to look for the data?

I opened up the files one by one and stumbled upon a clue after a few minutes, on line 37 in the Details Activity Class:

Reverse engineering this line of code, I traced the sandwich data back to the resources directory. I collapsed the values subdirectory and found the strings file down near the bottom:

Inside strings.xml, I found a dense blob nesting sandwich details inside of a string array tag.

Bingo.

Despite my desire to push through it, fatugue weighed heavy on my eyelids as I took in the time: 1:35 am. I’d been watching instruction videos and working on toy apps for 4 hours by that point when the system notification popped up: battery at 5% charge. I closed my laptop, resolving to give it a fresh go after getting some sleep.

Data Model Mapping

Abstracting Layers + Modeling Flow.

The next night, rather than diving in head first, I took a detour and opted for doing a data mapping exercise to organize my scattered thoughts. I opened up Microsoft Word, and pulled up a fresh copy of my data model mapping template that I typically used to pre-process some of my freelance projects.

After about 30 minutes or so of going back and forth between the starter code files and the data model map gradually that gradually started to materialize in Word, absorbing idiosyncrasies of the code in the process, I managed to abstract and visualize three layers — a Data Layer, a Serialization Layer, and a UI Layer.

Mapping the data flow helped me to better compartmentalize the app project into a few manageable phases that fostered better understanding of how all the classes would fit together to display sandwich details in a layout.

Here’s what I came up with:

With this as a guide, I ventured forward to the next part of the journey.

The Implementation Phase

Getting to the Code.

I narrowed my focus on the 4 pertinent files referenced in my data model map:

I set a goal for night 2: finish implementing the JavaUtils class and by so doing, knock off 2 core rubric requirements.

random note :

In real-life, the core functionalities of this project could easily be realized with any one of several 3rd party libraries, but implementing this from scratch was a great learning experience.

Accessing the Data

The time had come to drill into this data. I brought my strings resource file to the foreground and scrolled down to the string array to re-examine its items:

Hmm. Something new.

Up until that point, I’d only ever parsed JSON objects. A slight panic started to set, as I began to wonder whether I’d missed something from the lectures.

How is this going to work?

JSON data is parsed correctly to a Sandwich object in JSONUtils class.

I switched tabs again to re-examine the JsonUtils.java file. The null-returning static method at the heart of the class took in a a single stringified JSON parameter and outputted a serialized Sandwich object.

For that to happen, there’d need to be a conversion of some sort, from the single primitive string to a parsable object with accessible keys. A JSON object.

Focusing on Chrome in a dual-window view, I searched the Android’s developer docs for any libraries that specifically dealt with JSON and discovered this:

the json library for Android

Digging deeper into that JSONObject Class, the public constructors told me everything I needed to know:

Easy enough. The JSONObject Class maps key-value pairs of a passed in JSON string. I created a new instance of the class called “base” to convert the string argument:

Gist: JsonUtils-step1.java

Put another way, I took the JSON string parameter that originally looked like this:

and transformed it into a JSON object that looked like this:

Dope.

As a precautionary measure, I wrapped this statement — the first of several statements in this method’s logic — in a try/catch block to catch errors and prevent app crashes:

Gist: JsonUtils-step2.java

Ok.

With the data accessible in the appropriate structure, it was time to iterate on this process but this time with the object’s keys.

Parsing the Object

Referencing my data model map again, I realized a new hurdle to parsing the keys: anomalies. For example, some keys held string values, while others held object values, and the ingredients key mapped to an array.

Recalling that the json library also made a JSONArray class available, I got to work on pseudo coding my approach:

Gist: Json-Utils-step3.java

At the crux of it, the pseudo code detailed the process of isolating the keys of the base, de-stringifying the mapped-to values as necessary, and storing references of each in autonomous variables. Writing out the Java syntax was a cinch, from this point:

Gist: Json-Utils-step4.java

Satisfied with this approach, it was time to finish off the implementation by handling the final facet of the method — using all of these parsed keys as arguments to a Sandwich constructor.

Serializing Models

I’d made serious traction towards my goal but felt myself getting tired as the clock struck 2am.

Don’t let up, I uttered, determined to cross this task off my list.

I opened up the Sandwich.java class and examined the public constructor to ensure I had all the necessary pieces.

Check.

In the final stretch of the night, I inserted a closing statement to the try block that returned a new Sandwich model instance. The parseJsonData method was ready to be called from the Details Activity class:

Gist: JsonUtils-step5.java

Awesome.

I looked over the code, made the git commit, and called it a night.

Implementing the Logic Behind the UI

populateUI.

“So, findViewById() functions like getElementsById in JavaScript…”

Things started to sync by the third night.

By that point, total project hours spent summed to something like 10. Reviewing the rubric and my data model map one more time helped center my focus on the method — populateUI — being called from the onCreate lifecycle method in the Details Activity class:

Scrolling further down the class, I found its empty method definition.

Transposing what I already knew about helper methods from JavaScript, I easily identified populateUI as one of those types of functions. Just, written in Java. For Android.

I took in the Details Activity class in its entirety before attempting to even pseudo code.

It finally clicked that Android Activity classes started out as clean manifests that cycle through pre-defined processes. Should no tweaks, no overrides, be made, the life of the activity amounts to straightforward nothingness. The Activity just runs until destroyed.

When lifecycle methods get overridden, the changes that we make and the helper methods we create and employ (to make our code human-readable) ultimately make up the functionality, the uniqueness, of the overarching Activity.

Nothing profound, just new intuitions from late-night rumination about the art of the whole thing.

Anyway, back to the code, the Details Activity class in the starter code already provided and setup a few of the fixings needed to display a layout — the toolbar, grabbing intent extras from the previous activity, etc.

Process of elimination made it reasonable to deduce that populateUI handles data-binding. I commented out the pseudo code to work through its logic:

In the process of fleshing out this method, my intermediacy with OOP languages allowed me to see the parallels between the getElementById method in JavaScript and the findViewById() method. Both aided in accessing objects that rendered in a relative layout — be it the DOM or a layout resource.

I also gained a new appreciation for Android Studio and the way file syncing in the IDE stores resource names in order to intuit autocompletion. The whole flow started to feel like second nature and translating the pseudo code to Java felt more straight forward than the night before:

Gist: populateUI.java

Done.

I ran an Android Studio emulator to confirm that the data displayed correctly, as required (which it did), to cross off the third core requirement, but ran into a new issue. The layout looked awful. As someone overly sensitive to the look and feel of an application, it became clear that much more work needed to be done.

My Slight Deviation

Creating A More Sensible Layout.

The following night, I set a new goal (the final goal): knock out the design portion of this project in its entirety.

I took a look at the grading rubric one last time, to cache the last 2 requirements to my short-term memory. The first…

Detail layout includes a ScrollView so all the details are visible in small screen devices.

as a precursor to the last…

Sandwich details are shown in a sensible layout. For example, ingredients appear next to the ingredients label.

Paraphrased: the layout file activity_detail.xml needed to be refactored to include a ScrollView that nests a reorganized sequence of the provided TextViews.

A more sensible layout

A quick fix. After re-arranging the views and nesting the stack of them in a ScrollView, I ran the emulator again to check out the design.

Satisfactory but not satisfying. Time to get inventive.

Switching gears to designer mode, I launched Sketch to mockup what felt like a more aesthetically pleasing layout. 45 minutes in, I came up with a UI concept that I reasoned would: (1) provide a more structured browsing experience and (2) fragment the sandwich details for potential app use cases (e.g., trivia or recipe lookup) — right from the get-go.

The mockup ended up looking like this:

(This particular wireframe was created with NinjaMock.)

Much better.

Of course, this design warranted changes to the code.

Refactoring My Logic

My research on implementing a tabbed layout led me to an awesome tutorial by Mohit Gupt.

Digesting his example and considering how it might work in the context of my application, I knew I had to add a few more classes to my source code: two tab fragments and one page adapter:

We’d learned about fragments to a certain extent during the Nanodegree’s first term, but opting to implement this layout of my own volition, with creative license, raised my intuitions — about the parent-child/activity-fragment relationship and the trickle-down paradigm — to a higher power.

In terms of displaying sandwich details, I had to split up the statements in the populateUI helper method, initially housed in the Details Activity class, and distribute them between the two tabs:

Gist: Tab1.java
Gist: Tab2.java

random note:

I created two additional helper methods — edgeCase and makeList — to handle missing data occurrences and formatting lists, respectively. Code for these methods can be found here.

Nice. I had my two tab classes and all the pieces needed to implement PagerAdapter’s getItem method:

Gist: PagerAdapter.java

I felt everything coming together at this point, but before I could handle the final logistical step — inflating the tab layout in the Detail Activity — I’d need to refactor my layout files a bit.

Refactoring My Layout

The whole parent-child paradigm lent itself to the layout files, as well.

Instead of the activity_detail.xml file housing all the TextViews, my refactored activity layout functioned like a parent layout that instead housed a view for tabs (a TabLayout) and a view for the fragment pager (a ViewPager), stacked one on top of the other. The fragments worked like child layouts, in this case:

An even more sensible layout.

After making the changes, I recanted the populateUI statement and replaced it with a new method, called inflateTabs:

inflateTabs did as the name connoted: it created the TabLayout and ViewPager objects and provided the support needed to inflate the two tab fragments:

Gist: inflateTabs.java

I ran the emulator again, feeling good (initially) that all the core requirements had been met. However, viewing the device in landscape orientation introduced yet a new issue: responsiveness.

Making the App Responsive

Thankfully, making the layout responsive ended up being a pretty easy gig. I started by creating a new folder for landscape layouts under resources, then created a new layout file for the detail activity:

For the landscape layout, I went with a 50/50 split screen concept, with the sandwich image on the left and the tabs on the right.

Here’s the breakdown:

I ran the emulator one last time at about 3am in the morning and exhaled when everything looked decent.

What a journey. I closed my laptop, exhausted but lit with the sense of accomplishment.

The next day I pushed my local files to GitHub and submitted my project for review. Within 24 hours, I received word that I met all the specs (woo-hoo!) and received loads of inline feedback on my implementation!

Reflections

Closing Thoughts.

What I loved about this project

In hindsight, this was a special project for me. I spent an approximate 36 project hours from start to finish and challenged myself to go beyond the requirements.

The app catalyzed my curiosity about developing for Android and incited a fire that would fuel my drive through even the worst moments of the more difficult projects in the program to date.

Problem-solving my way through issues with the introduction of new features made me realize just how much I love developing enjoyable experiences for mobile.

What I could’ve done differently

Of course, having learned more about several aspects of the Android development lifecycle, I recognize areas that could be improved.

For example, some of my helper methods could have been decoupled from my fragment classes and outsourced to the utility package to keep my code D.R.Y.

Also, the font-size could’ve been larger to increase visibility and accessibility.

The additional toolbar feels a bit unnecessary (a simple divider probably would look better), in retrospect, which would omit my urge/the need to center the redundant Sandwich title under the image in portrait view.

With little time available, I decided to move on and incorporate my learnings into future projects along my journey.

The full code for this app can be found on GitHub.

--

--

AnnMargaret Tutu
Journeying Through Android Development: Unpacking My Projects from the Udacity-Google Nanodegree

Research Software Engineer (ML, DL, Blockchain, Android), budding cryptologist, writer and aspiring polymath.