Insider's Guide to Udacity Android Developer Nanodegree Part 7 - Full Stack Android |
Written by Nikos Vaggalis |
Monday, 23 April 2018 |
Page 3 of 8
Making the HTTP requests from AndroidMaking those requests from within the Android app required mapping them to equivalent Retrofit interfaces: That is mapping /smartphones/json to
("kind" takes the value of "smartphone","smartwatch" or /tablets1/smartphone/json to
and /tabletdetails/json?id=858 to:
Note the @Headers, @FormUrlEncoded and @POST annotations which get translated to their respective HTTP headers and actions. The actual Retrofit call implementing the ISendJSON Interface takes place inside method sendValuesSync()
Two takeaways.First, "sendValuesSync()".Does it mean that the Retrofit network calls are launched synchronously? Second, the "menuValuesSingleton" object.What's it for and why Singleton? First, let's take a look at "sendValuesSync()". The way a user interacts with the app in filtering devices by specifying criteria goes like: 1.Inside the Filter screen the user tweaks the UI.For example he sets the Screen Size slider's search range to 3"-5.5". 2.User presses the button marked with a "check" at the bottom of the Filter screen to commence the search.This action will end the Filter screen and bring back the Listing screen which is now filled with the list of devices matching the search. 3.To revise the search the user has to jump to the Filter screen again, which remembers the last performed search so that the new search can start from that point over with any extra criteria added up.This means that tweaking the FCamera slider initiates a new search which uses both the previously set Screen Size's ranges AND the new FCamera ones.
menuValuesSingleton passed forth and back 1.Listing screen -->to Filter screen.177 devices
2.Pressing the "check" button goes back to Listing screen.166 devices.
3.Then to Filter screen again amending the search
4.Pressing the "check" button goes back to Listing screen.27 devices.
So in order to maintain the state between the Listing and the Filter screens I needed an object which could be passed back and forth but also be able to keep track of its state.Therefore the singleton class RetrofitSendJSON was born together with its inner associated class MenuValues, that would span the life of the application.
In order for the MenuValues' instance menuValuesSingleton to be able to be passed around, it first had to be Serialized, or better said, Parcelized. Instead of going through that manually, I used the marvellous Parceler library which just requires annotating the class with @Parcel.Before passing on the object you wrap it with Parcels.wrap, while when you receive it you unwrap it with Parcels.unwrap. One caveat though .Initially I had my MenuValues's fields defined as private:
but upon building the project I was confronted with: F:\Udacity\smadeseek\app\src\main\java\ So in order to avoid taking that performance hit, I was forced to turn them into public. As far as calling Retrofit synchronously, I wrapped that call inside a Loader something that bore distinct advantages.As well known, a Loader is ideal for performing asynchronous operations independently of the lifecycle of the Activity.In case the Activity/Fragment gets destroyed due to a configuration change taking place like the screen rotating, the Loader would continue retrieving the data from the web, reattaching itself to the Activity upon it being recreated in order to make the data available to it.No memory leaks, no blocking the UI thread. The same however does not stand true when initiating a network call through a simple AsyncTask or even an asynchronous Retrofit call.Thereby by wrapping the Retrofit call inside the Loader I've used the Loader's benefits to my advantage. @Override public Pair<Device,String> loadInBackground() { try { if (RetrofitSendJSONobj.getMenuValues(). getJsonWithMenuData()==null) { RetrofitSendJSONobj. getMenuValuesJSONSync(); } Device device = RetrofitSendJSONobj. sendValuesSync(); Of course I could had fired the Retrofit request within the Loader itself in an asynchronous fashion but that would be an asynchronous task, the Loader, firing another asynchronous task, the Retrofit, putting them out of sync.What I wanted was for the Loader to wait for the Retrofilt call to complete in order to fetch the data.Alternatively, I could had fired a callback upon Retrofit's completion, but doing so inside the Loader really didn't make much sense. tip: Always use the Support Library versions (android.support.v4.app.*) for both Loaders and Fragments as the Framework's ones (android.app.*) have been officially deprecated in Android P.
|
Last Updated ( Monday, 23 April 2018 ) |