Yesterday I covered a lot of information about Intents and showed you a lot of different things you can do with intents.  Today as we continue the 31 Days of Android, we’re going to talk about a few more ways that Intents can be used.  As a reminder, Intents are messages that you can use to communicate between parts of your application or with the Android operating system itself, and there by other applications.  You can download the starter code we’ll be using today here.

 

Checking for Intent Responders

Yesterday I demonstrated how to do a number of different things via Intent.  I also specified that for many of them, you’d want to test on an actual device and not the emulator because the emulator doesn’t have the necessary components installed.  For example, the emulator doesn’t have the Android Marketplace.  Sicne the market isn’t installed, there isn’t any (easy) way to install applications to the emulator.  Open up your src/com.daytwentyseven/DayTwentySevenActivity.java class and locate button2’s onClickListener.  Let’s add the code back in that will launch the Android Marketplace application and search for an app:

button2.setOnClickListener(new OnClickListener() {            
    public void onClick(View v) {
        Uri marketUri = Uri.parse("market://search?q=com.google.android.apps.plus");
        Intent marketIntent = new Intent(Intent.ACTION_VIEW).setData(marketUri);
        startActivity(marketIntent);
    }
});

Now if you run this on a device with Marketplace installed, it will come up and search for Google Plus.  If you run this on an emulator though, your app will crash and in LogCat you’ll see this error:

android.content.ActivityNotFoundException: 
No Activity found to handle Intent 
{ act=android.intent.action.VIEW dat=
market://search?q=com.google.android.apps.plus }

Android doesn’t handle not having any thing to process an Intent very well.  Thankfully, they’ve given us a way to check to see if an Intent has a handler before calling it.  To do this, you need to get a reference to the PackageManager class.  The PackageManager can be used to retrieve information on things isntalled on the device.  In this case, you want to get info on applications that can respond to your Intent.  To do this you use the queryIntentActivities method and pass in the Intent you’ve created.  This will return a list of ResolveInfos with information about the Activities that will respond:

button2.setOnClickListener(new OnClickListener() {
    public void onClick(View v) {
        Uri marketUri = Uri
                .parse("market://search?q=com.google.android.apps.plus");
        Intent marketIntent = new Intent(Intent.ACTION_VIEW)
                .setData(marketUri);
 
        PackageManager pm = getPackageManager();
        List<ResolveInfo> list = pm.queryIntentActivities(marketIntent,
                PackageManager.MATCH_DEFAULT_ONLY);
        if (list.size() > 0)
            startActivity(marketIntent);
        else {
            Toast.makeText(getApplicationContext(),
                    "Sorry the market is not installed",
                    Toast.LENGTH_LONG).show();
        }
    }
});

Now when you run your app on a device (with the Marketplace) it will still load the market like you want (you’re still calling startActivity) but if you run it on an emulator, it will show a toast instead:

Showing toast if market isn't installed

Now you should be able to use this to gracefully handle any app’s not being installed that you want to launch from an Intent.  Remember that you’ll never know for sure if the device running your application is capable of handling an Intent so it’s always better to check than to assume.

I'm a little short for time today so we'll continue with, and wrap up, our talk about Intents, tomorrow.


Chris Risner