Welcome to part 2 this review of the Pluralsight course Android Programming with Intents by Jim Wilson
Jim has over 30 years of software engineering experience, with the past 15 years heavily focused on creating mobile device and location-based solutions. He has co-founded multiple software-related startups and has served in a consulting role at several more.
After nearly a decade as a Microsoft Device Application Development MVP, Jim now focuses on developing Android and iOS device applications. Jim’s passion is mentoring software developers. He blogs at hedgehogjim.wordpress.com.
Android Programming with Intents is the 6th course in the Pluralsight learning path for Android, and this month I am reviewing every course in this learning path.
Component activation with intents
Activating components with Intents
In the previous module we learned that components are activated by Intents, and the three types of components are Activities, Services and BroadcastReceivers.
But how are they activated? We use a different method depending on which component type we want to activate:
- Activities are activated with startActivity
- Services are activated with startService
- BroadcastReceivers are activated with sendBroadcast
Intents can be sent by programs, and they can also be sent by the Android system.
There are a few different types of Intent, and Jim begins by explaining the simplest of these.
Explicit Intents
- Contains the type information of the component
- Always directed at an instance
- All other content ignored
Jim then discusses Intent activation behavior, and makes the point that Intents provide much more than just simple object creation: they’re about component activation and giving us a mechanism for component management.
We express what we want to happen, and the system routes that for us.
Sending Intents often results in a new component instance being created. But in some cases, sending Intents can route the Intent to an existing instance.
Accessing the activating intent
When we’re working with a component that receives an intent, we need to access the contents of it. And each component accesses intents differently.
With Services, the Intent is passed to the onStartCommand method.
With BroadcastReceivers, the Intent is passed to the onReceive method.
With Activities, the intent is accessed by calling getIntent.
Demo: Activating components with Intents
Jim uses IntelliJ IDEA to demonstrate the IntentBasics example. It’s a very simple project with just three classes in it:
- MyActivity.java
- OtherActivity.java
- MyService.java
First, Jim writes a method called showOtherActivity which creates an explicit Intent and calls startActivity.
Then we see runService getting written. Again this uses an explicit Intent. It calls startService.
We run up the app in an emulator, and it has buttons for “Show Other Activity” and “Run Service”. Jim clicks these and explains the code in the debugger.
In the latter part of this lesson, Jim adds a flag to the activity Intent: FLAG_ACTIVITY_SINGLE_TOP.
Implicit intents and intent filters
Explicit intents are the easiest to create, but implicit intents unlock the full power of the Android platform.
Implicit intents rely on an action category and data values.
The component resolution relies on components having provided intent filters. The component activation works the same for both implicit and explicit Intents, but the key difference is how the components are selected.
Implicit Intents don’t contain a component name. You cannot put a component name into it, only the action category.
Jim also discusses how components provide filters to support implicit intent activation. We see an example showing that a single component can provide multiple intent filters.
Intent action tests
With implicit intents, instead of dealing with component types, we deal with testable members such as the action value.
This can be any string value. Jim recommends using package-style naming such as “com.pluralsight.action.DO_WORK”
Android predefines a number of action values for us.
Jim says much of what we do with Intents has to happen inside our manifest file. For example:
<action android:name="android.intent.action.MAIN" />
Unfortunately we can’t use constants in XML, so we need to use the string values and check our spelling carefully.
Although an intent filter can have multiple actions, an intent contains at most one action value.
Action matching
Jim describes the action matching rules.
Action value equality is tested using a case-sensitive string comparison, so check the casing of each letter in the string is correct.
A match is true if the intent action is contained in the filter action list. The filter can define any number of actions.
Something that Jim says we need to watch out for is it’s legal to have a filter with no action value, but that will never match any intents.
Attaching information
Also in this lesson, Jim explains Intent extras. These are name/value pairs and the information can be strongly typed.
These extras aren’t included in the component resolution and are not used by the Intent filters.
Demo: Intent action tests
This demo builds on the IntentBasics projects we saw earlier on in this module.
Starting in MyService.java we see the onStartCommand method extended to check for action values of “com.pluralsight.action.LOG_TIME” and “com.pluralsight.action.LOG_DATE”.
By the end of this lesson, we see the app running in the emulator. Jim goes into the settings screen and Force stops the IntentBasics app. He also turns on Airplane mode.
We can still get all of the events. We look at the logs in logcat and see that by using implicit intents, we can communicate across processes.
Intent category and data tests
Jim says Categories subdivide component types, dividing eligible components into subgroups.
The style of defining a category is like we saw for defining an action:
com.pluralsight.category.NEW_CATEGORY
We learn about the category matching rules here. There are some categories which are required in a filter even when they don’t exist in an Intent. The most common example of this is CATEGORY_DEFAULT.
CATEGORY_LAUNCHER is another special case category which is required for an Activity to show in the Android launcher screen.
Jim says the data test are by far the most complicated, and this is covered a lot more later in this course.
In this lesson we learn that a data test is a 2 part test:
- A type test (the Mime type). What kind of data can we work on?
- The Uniform Resource Identifier. Where the data is located
Jim explains the parts that make up a URI, and he covers the general data matching rules.
All of the tests are case sensitive (differing from the URI RFCs), and several factors can complicate data matching tests: Wildcards, Inferred types, Inferred schemes and URI tests that do not include all parts of the URI.
Jim ends this lesson by running through a number of scenarios that are considered a match.
Demo: Intent category and data tests
We continue with the IntentBasics project that we’ve been build in this course, and look at how categories and data effect the program.
We begin by creating a HelloWorld activity, and then create an Intent in a showHelloWorld method.
Our app crashes! How can this be? Logcat gives us the answer:
ERROR/AndroidRuntime(3010): FATAL EXCEPTION: main
android.content.ActivityNotFoundException: No Activity found to hand Intent { act=com.pluralsight.action.HELLO_WORLD }
Our action is defined in our manifest, so what’s the problem? It’s what we learned in the previous lesson: in order for an activity to be chosen, it has to be in a default category.
In the Android Manifest, we add a new category to our intent-filter:
<category android:name="android.intent.category.DEFAULT" />
Next we add another activity with the same intent filter in a separate project. When we run it in the emulator, we are prompted to choose which Activity we want to launch.
This is because we have a tie, and it is a feature of Android allowing us to extend the platform.
Jim says ties behave differently which each component type. In the case of broadcast receivers, every matching component is fired.
When there is a tie between services, the choice of service is automatic and arbitrary, so we need to be careful to avoid services with duplicate intent filters.
We end this lesson seeing the app in the emulator with a “Show PS Homepage” button opening up Pluralsight in the browser for us.
Getting a closer look at intent resolution
Jim says there are some situations where it isn’t obvious how an Intent will be resolved.
If we need to know more about the resolution process, we can log information.
There is a flag called FLAG_DEBUG_LOG_RESOLUTION. When this is added to the Intent, the whole resolution process is logged out to Logcat. It shows us things such as:
- What did the intent contain?
- The list of matching components
- The selected matching component
We can also use the PackageManager class to get an even closer look. It has several query methods: