How to start an IntentService from a WakefulBroadcastReceiver

overactor picture overactor · Sep 1, 2014 · Viewed 22.6k times · Source

I have an application, which you should be able to recreate entirely and very easily with the code I'll post in this question. Here's the Manifest file:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcasttest"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="19"
        android:targetSdkVersion="21" />

    <uses-permission android:name="android.permission.WAKE_LOCK"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <activity
            android:name="com.example.broadcasttest.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <receiver
            android:name="com.example.broadcasttest.TestReceiver"
            android:label="@string/app_name"
            android:enabled="true" >
        </receiver>

        <intentservice 
            android:name="com.example.broadcasttest.MonitorService"
            android:enabled="true" >
            <intent-filter>
                <action android:name="com.example.broadcasttest.MonitorService" />
            </intent-filter>
        </intentservice>
    </application>

</manifest>

As you can see, the contains an activity, a (wakeful) broadcast receiver and an intentservice, all in the same package. The activity gets started at launch, here's the code:

package com.example.broadcasttest;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;


public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        sendBroadcast(new Intent(this, TestReceiver.class));
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}

This succesfully triggers the onReceive function of TestReceiver.

package com.example.broadcasttest;

import android.content.Context;
import android.content.Intent;
import android.support.v4.content.WakefulBroadcastReceiver;

public class TestReceiver extends WakefulBroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        //Intent service = new Intent("com.example.broadcasttest.MonitorService");
        Intent service = new Intent(context, MonitorService.class);
        startWakefulService(context, service);
    }

}

This is where things go wrong though, I placed a breakpoint in the onReceive function and it definitely gets called. However, the MonitorService class never gets reached. I placed a breakpoint in the onHandleEvent function, but it seems like it never gets that far. Here's the code for this class:

package com.example.broadcasttest;

import android.app.IntentService;
import android.content.Intent;

public class MonitorService extends IntentService {

    public MonitorService(String name) {
        super(name);
    }

    public MonitorService()
    {
        super("MonitorService");
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            TestReceiver.completeWakefulIntent(intent);
        }

    }

}

As you can tell from the commented line in the TestReceiver class, I've tried using an implicit intent instead of an explicit one. I've also read this question and tried everything mentioned there. Am I missing something here? I'm running this on an emulator (Nexus7 API L).

Is there anything I'm missing here?

Answer

Pankaj Kumar picture Pankaj Kumar · Sep 1, 2014

There is no tag as <intentservice> in Application Manifest. IntentService is a subclass of Service, so you need to declare it as service in manifest.


Change

<intentservice 
    android:name="com.example.broadcasttest.MonitorService"
    android:enabled="true" >
        <intent-filter>
            <action android:name="com.example.broadcasttest.MonitorService" />
        </intent-filter>
</intentservice>

to

<service 
    android:name="com.example.broadcasttest.MonitorService"
    android:enabled="true" >
       <intent-filter>
           <action android:name="com.example.broadcasttest.MonitorService" />
       </intent-filter>
</service>