Insider's Guide To Udacity Android Developer Nanodegree Part 3 - Making the Baking App
Written by Nikos Vaggalis   
Monday, 03 July 2017
Article Index
Insider's Guide To Udacity Android Developer Nanodegree Part 3 - Making the Baking App
Step 1 Fragments
Step 2 - Libraries & Networking
Step 3 - Adding Exoplayer
Step 4 - Widgets
Step 5 - The Widget Provider
Step 6 - UI Testing
Step 7 - Testing Intents


Step 5 - Hooking up the Widget provider


While this last step sets up the widget's infrastructure, I haven't yet made the connection to its RecipeDetailActivity so that when RecipeDetailActivity is updated with new data, it also feeds the new list of ingredients to the widget.

The lesson's exercise has a PlantActivity calling into a PlantWateringService IntentService as the mediator of communication between the PlantActivity and its home screen Widget.As soon as PlantWidget's drop/watering icon is clicked, an IntentService encapsulating an action of ACTION_WATER_PLANT is fired, which is sent to the PlantWateringService which in turn handles the matter in its onHandleIntent callback


@Override
    protected void onHandleIntent(Intent intent) {
        if (intent != null) {
            final String action = intent.getAction();
            if (ACTION_WATER_PLANT.equals(action)) {
                final long plantId =
                           intent.getLongExtra(EXTRA_PLANT_ID,
                                    PlantContract.INVALID_PLANT_ID);
                handleActionWaterPlant(plantId);
            } else if (
                ACTION_UPDATE_PLANT_WIDGETS.equals(action)) {
                handleActionUpdatePlantWidgets();
            }
        }
    }


image22    
When ACTION_WATER_PLANT.equals(action) is on, handleActionWaterPlant is called with the plantId in question. handleActionWaterPlant works in a background thread and updates the plants' database table column COLUMN_LAST_WATERED_TIME through the PlantContract content provider.As a side note, this goes to  highlight the value of the Content Provider as selfcontained piece of mediating, getting called from anywhere and from anyone.The lesson's exercise goes through the content provider to signal that the given plant should be watered and in turn waters it by updating the database.

I adopted the same approach for the Baking App in that the RecipeDetailActivity calls the UpdateBakingService just like the PlantWateringService, but with the difference that it sends the ingredient list to the widget:
 

 
UpdateBakingService.startBakingService(
                             getContext(),recipeIngredientsForWidgets);


I have to say that the lesson's exercise didn't tell the whole story, because instead of sending data from the Activity to the Service and from the Service to the Widget in order to directly update the widget’s UI, it made the update indirectly by going through the Content Provider, something that simplified the process. In my case it was necessary to feed the widget directly with the list of ingredients by passing to it an associated bundle.

The flow of the process began from the RecipeDetailActivity towards  UpdateBakingService, and from UpdateBakingService to  BakingWidgetProvider, with the UpdateBakingService broadcasting the special message "android.appwidget.action.APPWIDGET_UPDATE2" discussed earlier. BakingWidgetProvider then catches it together with the associated bundle, inside its onReceive callback.

 
private void handleActionUpdateBakingWidgets(
                              ArrayList<String> fromActivityIngredientsList) {
            Intent intent =  new Intent("android.appwidget
                                           .action.APPWIDGET_UPDATE2");
            intent.setAction("android.appwidget.action
                                                     .APPWIDGET_UPDATE2");
            intent.putExtra(FROM_ACTIVITY_INGREDIENTS_LIST,
                                                     fromActivityIngredientsList);
            sendBroadcast(intent);
       }


BakingWidgetProvider onReceive does the rest. It extracts the Ingredient list from the bundle and goes on to update the widget as previously described.


image23

All that remains is to see this in action. First of all let's create the widget - long press on the home screen and select Widget from the menu that appears:

image24

 

Browse through the list of all the widgets installed on the device by the various applications and find the BakingWidget.


image25

 

Then hold down and drag over the widget to the home screen.


image26
Run the app, navigate to the RecipeDetailActivity, minimize the activity to show the home screen and check that the widget is correctly updated with the list of the given recipe's ingredients.Then click on any of the widget's cells to summon back the RecipeDetailActivity at the state it was left off before getting minimized.

image27



Last Updated ( Monday, 20 November 2017 )