Page 6 of 8
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(); } } }
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.
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:
Browse through the list of all the widgets installed on the device by the various applications and find the BakingWidget.
Then hold down and drag over the widget to the home screen.
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.
|