Remember the Journey

“Finally I remembered what I had found in ultrarunning.  I remembered what I had lost.”

As I was reading last Monday morning, I came across this line from ultramarathoner Scott Jurek’s book Eat & Run.

Throughout the week I reflected on this and on my own experiences training for my first marathon.  I thought of how most of my favorite memories of running were of training runs or recovery sessions where I was able to lose myself in pushing my limits or surprise myself at what I was capable of.

As the week went on I started to realize how these same thoughts were present when looking back at my experiences as a software developer and as a student.

Part of what drew me to software development were the endless possibilities, and the idea that “if you can dream it you can build it”  For me, these ideas are inherently linked with the ideas of continuous education and growth.  This is a core part of who I am, and i think is one of my greatest traits.  I like to think of my education and career as a journey that will never end, but will evolve over time and be filled with new information and technology.  These thoughts keep me engaged at work and motivated outside the office to keep growing.

It’s easy however to lose site of these ideals when presented with deadlines, changing requirements, endless meetings, and the ups and downs of every day life.  Cultivating a new skill is sacrificed for an extra feature this sprint; a more elegant/educational architecture is abandoned to avoid extra code changes; etc.

It's important to remind ourselves why we do what we do... we shouldn't have to sacrifice our happiness for a deadline Click To Tweet

It’s important to remind ourselves why we do what we do, what keeps us excited, and to remember that while time is money, and deadlines are important you shouldn’t have to sacrifice your enjoyment of what you do.

Happier workers are more productive, and tend to avoid burnout better.  They have greater sense of fulfillment, and are more likely to be advocates for a company/team/product.

Therefore, I think it’s crucial that we all try our best to look back, reflect, and to stay enthusiastic, keep a sense of wonder at being a “code ninja” or “keyboard wizard”, and don’t lose sight of the journey.


I love to meet/talk/discuss and help where I can. If you want to chat or ask a question you can follow me on Twitter, YouTube, Instagram and Facebook.

Check Out My YouTube Channel

Implementing a Collapsing Toolbar

Implementing Material Designs

With the continuing adoption of Material Design across Android apps, I think there is a bit of a divide between these beautiful/functional designs that are being produced, and the technical knowledge of actually implementing those designs. This gap between design and implementation was recently narrowed with the release of the Design Support Library. There is now an extremely useful set of widgets specifically to make the implementation of Material Design easier on the Android platform.

CollapsingToolbarLayout

I recently spent some time exploring one of these new widgets: the CollapsingToolbarLayout, and wanted share some of what I discovered in implementing an expanded height, collapsing toolbar. The objective of this demo is to simply create an extended height AppBar that contains a title and animates to a standard AppBar height in response to a user scrolling action.

Setup

First off, make sure you have the required dependencies: - `compile 'com.android.support:appcompat-v7:23.0.1` - `compile 'com.android.support:design:23.0.1` Next, ensure you have a new project containing a single `AppCompatActivity`. The code for this activity should look something like this to start:
 public class MainActivity extends AppCompatActivity {  
   @Override  
   protected void onCreate(Bundle savedInstanceState) {  
     super.onCreate(savedInstanceState);  
     setContentView(R.layout.activity_main);  
   }  
 }  

Create the root layout

For this simple implementation, all the magic takes place within `activity_main.xml`.

First off, update the root element of the layout to be a `CoordinatorLayout`, and make sure to fully qualify the `CoordinatorLayout` class name since it comes from a support library. This will save you from wonderful "Class not found" errors when you deploy and run your app.

 <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"  
   xmlns:tools="http://schemas.android.com/tools"  
   android:layout_width="match_parent"  
   android:layout_height="match_parent"  
   xmlns:app="http://schemas.android.com/apk/res-auto"  
   tools:context=".MainActivity">  
   <!--AppBarLayout will go here-->  
   <!--Scrolling content will go here-->  
 </android.support.design.widget.CoordinatorLayout>  

Setup the scrolling content

Now it's time to setup the scrolling content. This is the layout that the user will interact with that will cause the toolbar to collapse and expand.

This example will keep things very simple. The scrolling content will simply consist of a `NestedScrollView` containing a `TextView` displaying a very long string. Notice the use of NestedScrollView rather than ScrollView. `CoordinatorLayout` knows how to interact with `NestedScrollView`, so If you want coordinated scrolling behaviors, you must use it over `ScrollView`.

The scrolling view must be a direct child of the `CoordinatorLayout` as it will later interact with its sibling view (the `AppBarLayout`).

 <!-- Scrolling Content -->  
 <android.support.v4.widget.NestedScrollView  
 android:layout_width="match_parent"  
 android:layout_height="match_parent"  
 app:layout_behavior="@string/appbar_scrolling_view_behavior"  
 android:padding="@dimen/activity_horizontal_margin"  
 android:clipToPadding="false"  
   >  
 <TextView  
   android:layout_width="match_parent"  
   android:layout_height="wrap_content"  
   style="@style/TextAppearance.AppCompat.Large"  
   android:text="@string/lorem_ipsum"  
   />  
 </android.support.v4.widget.NestedScrollView>  

Notice the `app:layout_behavior` attribute on the `NestedScrollView`. That attribute informs the `CoordinatorLayout` that the view scrolls and will allow other content to react to those scrolling events accordingly.

Time to add the AppBar

To add a `Toolbar` that can be expanded and collapsed three support library widgets can be used:

1. AppBarLayout
2. CollapsingToolbarLayout
3. Toolbar

These views will be nested in the order in which they were included above. They should be placed within the root layout as a direct child of the `CoordinatorLayout` and as a sibling of the scrolling content.

 <!-- AppBar content -->  
 <android.support.design.widget.AppBarLayout  
 android:layout_width="match_parent"  
 android:layout_height="192dp"  
 >  
 <android.support.design.widget.CollapsingToolbarLayout  
 android:layout_width="match_parent"  
 android:layout_height="match_parent"  
 app:layout_scrollFlags="scroll|exitUntilCollapsed"  
 >  
 <android.support.v7.widget.Toolbar  
   android:id="@+id/toolbar"  
   android:layout_width="match_parent"  
   android:layout_height="?attr/actionBarSize"  
   android:background="?attr/colorPrimary"  
   />  
 </android.support.design.widget.CollapsingToolbarLayout>  

There are a few interesting things in this layout to point out:

1. The expanded size of the AppBar is controlled by the height attribute of the `AppBarLayout`.

2. The collapsing behavior of the AppBar is controlled by the `app:layout_scrollFlags` attribute.  In the example above the `scroll` value specifies that the `CollapsingToolbarLayout` should respond to scroll events, and the `exitUntilCollapsed` value specifies that the AppBar should shrink in size until it reaches it's collapsed (min) height.
3. The min height is controlled by the height of the `Toolbar` within the `CollapsingToolbarLayout`

One of the great things about `CoordinatorLayout` and some of its supporting cast members is that the behaviors of different views can be easily customized through xml without ever touching your code.  This makes it very easy for a developer or designer to quickly try different behaviors withing having to modify any Java code!!!

And there you have it.  A simple implementation of a collapsing, extended height AppBar.  For a information you can follow the video link below, or you can check out the sample code on GitHub.

Video Tutorial
Sample Code

I love to meet/talk/discuss and help where I can. If you want to chat or ask a question you can follow me on Twitter, YouTube, Instagram and Facebook.

Check Out My YouTube Channel

Spotify Streamer

This demo illustrates the Spotify streamer app I worked on as a part of my Android Nanodegree program.

I enjoyed the opportunity to try my hand at implementing some interesting UX patterns and to work with media playback for the first time.

I didn’t get around to wrapping up the UI polish, but I’m still pretty happy about how this turned out as a short term project.


I love to meet/talk/discuss and help where I can. If you want to chat or ask a question you can follow me on Twitter, YouTube, Instagram and Facebook.

Check Out My YouTube Channel

MarvelAndroid

I’m happy to say that Beta 1 of MarvelAndroid is available!

What is it for?

This library is aimed at making it easier for developers to make awesome comic book apps with the Marvel Comics Api. There is a wealth of awesome Marvel content available through the api, and with MarvelAndroid quickly accessing that content is now easier than ever.

What can it do?

MarvelAndroid supports retrieving content for each of the 6 core entity types the API makes available:

– Characters
– Comics
– Events
– Series
– Stories
– Creators

This content can be queried in a number of ways. You can perform a general search to return all comics, all series, etc. Or, you could search for all comics associated with a specific event or maybe search for all characters whose name starts with “spider”.

See the Interactive Documentation for a full list of ways in which content can be queried.

Initialization

To use this library, you must first initialize it within your code using your own public and private keys acquired from the [Marvel Developer Portal](http://developer.marvel.com/).

 MarvelAndroid.initialize(context, "your private key", "your public key", cacheSize);  

Searching

Lets take a look at an example of searching for a content. In this case we want to retrieve all characters whose name starts with “spider”.

First, create a `CharacterQueryParams` object to define the characters query.

 CharacterQueryParams queryParams = new CharacterQueryParams();  
 queryParams.setNameStartsWith("spider");  

Next, get an instance of `CharacterEndpoint`.

 MarvelAndroid marvelAndroid = MarvelAndroid.getInstance();  
 CharacterEndpoint characterEndpoint = marvelAndroid.getCharacterEndpoint();  

Through the endpoint, characters can be return through a number of methods such as `getCharacter()` and `getCharactersForComicId()`. Each method has two forms as well. One that takes a callback, and another that returns an RxJava Observable.

 characterEndpoint.getCharacters(queryParams, new Callback<RequestResponse<Character>>() {  
   @Override  
   public void success(RequestResponse<Character> characterRequestResponse, Response response) {  
   }  
   @Override  
   public void failure(RetrofitError error) {  
   }  
 });  
 Observable<RequestResponse<Character>> characters = characterEndpoint.getCharacters(queryParams);  

Handling results

With the returned response, a list of characters matching the specified query can be accessed. The results are returned in pages, with a default page size of 20. The page size and current page offset can be set through the `CharacterQueryParams`.

 characterEndpoint.getCharacters(queryParams, new Callback<RequestResponse<Character>>() {  
   @Override  
   public void success(RequestResponse<Character> characterRequestResponse, Response response) {  
     List<Character> characters = characterRequestResponse.data.results;  
     for (Character character : characters) {  
       print("Name: " + character.name + " Id: " + character.id + " Description: " + character.description);  
     }  
   }  
   @Override  
   public void failure(RetrofitError error) {  
   }  
 });  

Lets add another endpoint

In the previous example, we retrieved a list of characters. Now, lets look at how you could retrieve a list of comics for a returned character.

 ComicQueryParams queryParams = new ComicQueryParams();  
 queryParams.setOrderBy(ComicQueryParams.OrderBy.Title);  
 for (Character character : characters) {  
  marvelAndroid.getComicEndpoint().getComicsForCharacterId(character.id, queryParams, new Callback<RequestResponse<Comic>>() {  
    @Override  
    public void success(RequestResponse<Comic> requestResponse, Response response) {  
     List<Comic> comics = requestResponse.data.results;  
     for (Comic comic : comics) {  
       print("Title: " + comic.title + " Description: " + comic.description);  
     }  
    }  
    @Override  
    public void failure(RetrofitError error) {  
    }  
  });  
 }  

Images

One of the best parts about comics, and Marvel’s API is all the incredible artwork that is available. For any entity, you can retrieve a partial url path that can be used to build a full url to an image representation of the entity. Each image can be accessed as a variety of variants which are documented here.

 comic.thumbnail.path + "/" + "image variant name" + "." + comic.thumbnail.extension  

http://i.annihil.us/u/prod/marvel/i/mg/2/e0/55d225446d1c0/landscape_medium.jpg

http://i.annihil.us/u/prod/marvel/i/mg/2/e0/55d225446d1c0/portrait_incredible.jpg

Use and Contribute

You can view/download the code at GitHub.

Please give feedback, log any issues you find, or create enhancement requests.


I love to meet/talk/discuss and help where I can. If you want to chat or ask a question you can follow me on Twitter, YouTube, Instagram and Facebook.

Check Out My YouTube Channel