Insider's Guide to Udacity Android Developer Nanodegree Part 7 - Full Stack Android |
Written by Nikos Vaggalis | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Monday, 23 April 2018 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Page 6 of 8
Filtering the Devices based on a range of specifications The action of customizing the search takes place inside the Filter screen.The options that you can filter by are :
To keep it light on the mobile side, most of the criteria available through the WebSite were left out, with only a few crucial ones ending up in the mobile application.However there were still limitations due to the HTML/webforms' handling of the Primary Keys of the underlying database tables.
Database diagram In data modelling one is not forced to keep a unique surrogate (artificial) PK the likes of a single column integer.One can very well have a single column natural key (a key that has business meaning) or even a composite (multicolumn) natural key. For example, an entry in the CPU table can be uniquely identified by the union of CPUType and CPUModel, a composite PK comprising of these two.
CPU table
But how can you model this composite key relation in a HTML form dropdown menu when there's a slot for just a single value? That is, the dropdown menu expects : <option value="Key"> Value </option> or interpolated: <option value="1"> Model : HELIOS X20 </option> thus the composite key doesn't fit the picture: <option value="HELIO,X20"> Model : HELIOS X20 </option> So to accommodate to the single value PK requirement, I've built an autoincremented Integer surrogate key, CPUId as in
Amended CPU table
CPUId PK
The template renders that data according to :
therefore the menu's entries would look like : <option value="1"> Model : HELIOS X20 </option> <option value="2"> Model : HELIOS X10 </option> <option value="3"> Model : MT 6223 </option> However, a single column PK can't shield from duplicate values creeping in as the following case demonstrates:
So aside from already possessing a PK in CPUId, I've also built a Unique Index comprising of CPUType and CPUModel to disallow these kind of attempts.(Violation of Unique Index when trying to insert HELIO,X20 a second time)
CPUType, CPUModel Unique Index The final result :
CPU table's data
Mapping the PK's to Android Spinners Since the website was built with this model in mind, the android app was once more hostage to the WebSite's intricacies.To map this PK relation to the equivalent Android Spinners, their underlying morphology had to change.So despite that the Spinners present text to the user, the behind the scenes actions are all tied to the underlying hidden integer PKs.So for example while the "Operating System" spinner displays "Android 4.4" , or "Android 6.0" these values actually get mapped to PKs 17 and 149 respectively.
Operating System spinner
Therefore the Spinner's Adapter had to be turned into a collection of HashMaps, with each HashMap entry (spinnerMap) filled as : HashMap<Integer, String> spinnerMap = that is HashMap<17, "Android 4.4"> HashMap<149, "Android 6.0"> so when the user selects "Android 6.0" to retrieve the list of devices that support this kind of OS version, what is actually POSTed is number 149 as in "OSId=149".
Comparing the devices The user can also add devices to a to-be-compared list by going to the device's detailed specifications screen, the Specs (PageFragment) and press the "Scale" icon from the expanding FAB
something that invokes a call to the underlying Content Provider in order to add a row to the COMPARABLES table
You can even compare phones to tablets or watches by adding them to this list which list can hold up to 4 devices, a condition checked against upon every time an insertion is attempted:
to-be-compared list
Note the custom exception NoMoreComparablesException which extends SQLException.It was introduced so that a different course of action can be taken when this condition is met.In this case NoMoreComparablesException signifies that the insertion attempt should be disallowed, also letting the user know by displaying a Toast carrying the message "Can't have more than 4 devices in the Comparables list!". Transferring the inner exception convention from C#, NoMoreComparablesException got wrapped inside a SQLException so that when catching the generic SQLException and noticing that it's inner exception part is filled, we can be rest assured that we're in fact dealing with a NoMoreComparablesException rather then a general abnormal operation denoted by SQLException. If all goes well and there's no more than 4 devices on the list, clicking on the green "Compare" button stacks the devices' specs side by side by utilizing the layout "fragment_page_comparables_detail" as their base View
"fragment_page_comparables_detail" layout
This View is repeated for each device on the list, so say for 3 devices on the list, 3 such views are placed adjacent to each other, each one filled with its assigned device's specs. "fragment_page_comparables_detail" layout repeated for each device
"fragment_page_comparables_detail" layout repeated for each device, scrolling down to check out the Hardware specification category
The processes of filling the layouts as well as placing them one after the other is being dynamically performed:
devicesArray contains the model ids (i.e 19,134,829) of the devices on the to-be-compared list, which sequentially forwards one by one to callbackTabletDetail in order to make the network call to retrieve the specs of the device. The specs are then stored in tabletDetailObj.This action takes place in the onResponse callback.In detail, what's really happening is that for each device, an instance of the "fragment_page_comparables_detail" layout is created and pinned onto the main layout according to layoutParamsPhonePort or layoutParamsPhoneLand. After that an EventBus event is fired to notify another part of the code to proceed with filling the newly instantiated layout with the specs of the device stored inside tabletDetailObj. This sequence, although done in asynchronous fashion, of adding and filling layouts one after the other as each device comes into play, should have been the bread and butter of 'promises' but Retrofit makes them available in its RxJava version.But even if they were available, most probably they wouldn't be a good fit for this case's intricacies.So in order to keep sequence in this string of asynchronous operations, a ReentrantLock was appointed as the traffic controller. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Last Updated ( Monday, 23 April 2018 ) |