Insider's Guide To Udacity Android Developer Nanodegree Part 2
Written by Nikos Vaggalis   
Monday, 24 April 2017
Article Index
Insider's Guide To Udacity Android Developer Nanodegree Part 2
Lifecycle issues
Preferences
Uploading the Project and Feedback

To meet the User Interface/Functionality specifications:

  • When a user changes the sort criteria (most popular, highest rated, and favourites) the main view gets updated correctly.
  • When a movie poster thumbnail is selected, the movie details screen is launched.
  • When a trailer is selected, app uses an Intent to launch the trailer.
  • In the movies detail screen, a user can tap a button(for example, a star) to mark it as a favourite.

To meet the Network API Implementation specifications:

  • In a background thread, app queries the /movie/popular or /movie/top_rated API for the sort criteria specified in the settings menu.

  • App requests for related videos for a selected movie via the /movie/{id}/videos endpoint in a background thread and displays those details when the user selects a movie.

  • App requests for user reviews for a selected movie via the /movie/{id}/reviews endpoint in a background thread and displays those details when the user selects a movie.

To meet the Data Persistence specifications:

  • The titles and ids of the user's favourite movies are stored in a ContentProvider backed by a SQLite database. This ContentProvider is updated whenever the user favourites or un-favourites a movie.

  • When the "favourites" setting option is selected, the main view displays the entire favourites collection based on movie ids stored in the ContentProvider.

It's apparent from going through that list that some chapters like the one on Background Services are not necessary for completing the project, therefore I skimmed over them, aiming to return at a later date when there's less time pressure.To save even more time I've broken the rules and applied everything I've leaned straight on to the project, rather than on to the Sunshine application first.

The Lifecycle unit makes it crystal clear from the very beginnings that developing for mobile is not the same as developing for desktop due to the limited resources available on mobile devices. This situation grants the OS the freedom to terminate any app whenever it sees fit, therefore you have to anticipate this as well as any other change in your app's state, like the Activity dying because of the device rotating. This awareness is made possible by subscribing to the various events that the application triggers throughout its lifetime, such as OnCreate, OnPause, OnDestroy, onSaveInstanceState etc

For this stage it's necessary to subscribe to the onSaveInstanceState event for storing each movie's properties (title, rating, overview etc) as well as MainActivity's RecyclerView LayoutManager's state. The issue here is that the MainActivity and all of its data are destroyed when the device's orientation changes, something undesirable as upon re-instating the activity we do not want to go through the expensive network calls again in order to retrieve the movie details that had already been loaded in the activity before it got destroyed.

 

device-2017-04-07-181046

MainActivity

Therefore, when it's time to leave MainActivity, typically when clicking on a movie's poster, and before opening ChildActivity which contains more details on the movie in question (backdrop image, title, overview, rating) , we save the MainActivity's state in a Bundle by subscribing to the activity's onSaveInstanceState event.

After returning to MainActivity from ChildActivity, we check whether MainActivity was in fact destroyed, and if so re-instantiate it by extracting its saved state out of the Bundle.

What's also in the Bundle is the MainActivity's RecylerViewer's LayoutManager's state which stores the position of the item the RecylerViewer was last scrolled to, as well as the RecylerViewer's Adapter's (MovieDbAdapter) contents, that is, the ArrayList containing all of the movies' instances that are displayed as thumbnail posters on the main screen. A movie's instance is an object that conforms to the following structure:

 
public class MovieDbData { public String myTitle; public String myImage; public String myOverview; public String myRelease_date; public int myId; public String myBackdrop_path; public String myVote_average;

But to be able to save a movie (MovieDbData) into the Bundle we first have to serialize it as a Parcelable object, which is way more efficient than its Serializable counterpart.

device-2017-04-07-181156

ChildActivity/Details Screen

Given the opportunity, I've also packed and passed the clicked on movie instance  from Main Activity to the ChildActivity as a Parcelable object:

 
 @Override
   public void onListItemClick(
MovieDbData clickedItemIndex) { Intent startChildActivityIntent =
new Intent(MainActivity.this,
ChildActivity.class);
Parcelable parcelableMovie = clickedItemIndex;
startChildActivityIntent.putExtra(getResources().
getString(R.string.put_extra_movie_details),
parcelableMovie);
startActivity(startChildActivityIntent); }

This was done so that upon entering ChildActivity in order to reveal more details on the chosen movie, we avoid calling the network again for retrieving the movie's details which we already have a copy of inside MainActivity's memory space; so why not take advantage of it?
 
Saying that, all networking access should be wrapped in an AsyncTaskLoader construct so that it is handled asynchronously and in the background.In contrast to the simple AsyncTask introduced in stage 1 of the project, AsyncTaskLoader is now the new recommendation because of its tight integration to the app's Lifecycle and its resilience to creating Zombie background threads to which AsyncTask is prone.

loader

 



Last Updated ( Monday, 20 November 2017 )