16

Possible Duplicate:
Android RuntimeException: Unable to instantiate the service

Trying to get GCM up and running but my device is sending a registration request, but getting no response back from the GCM server. Below I included my manifest and GCMIntentService definition, and my call to register with the GCM server. I've been staring at it so long I might be missing something obvious, if so I apologize.

All ideas welcome!

Here is my manifest:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="PACKAGE"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="15" />

    <permission android:name="PACKAGE.permission.C2D_MESSAGE" android:protectionLevel="signature" />
    <uses-permission android:name="PACKAGE.permission.C2D_MESSAGE" /> 
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.INTERNET" />

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

        <service android:name=".GCMIntentService" 
            android:enabled="true"/>

        <receiver
            android:name="com.google.android.gcm.GCMBroadcastReceiver"
            android:permission="com.google.android.c2dm.permission.SEND" >
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <action android:name="com.google.android.c2dm.intent.REGISTRATION" />

                <category android:name="PACKAGE.GCMIntentService" />
            </intent-filter>
        </receiver>


        <activity
            android:name=".MainActivity"
            android:label="@string/title_activity_main" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

</manifest>

Here is my GCMIntentService to handle the return from GCM:

import com.google.android.gcm.GCMBaseIntentService;
import android.content.Context;
import android.content.Intent;
import android.util.Log;


public class GCMIntentService extends GCMBaseIntentService {
    public static String TAG = "GCMIntentService";

    public GCMIntentService(String senderId) {
        super(senderId);
        Log.d("GCMIntentService", senderId);
    }

    @Override
    protected void onError(Context arg0, String arg1) {
        Log.d("onError", arg1);
    }

    @Override
    protected boolean onRecoverableError(Context context, String errorId){
        Log.d("onRecoverableError", errorId);
        return false;
    }

    @Override
    protected void onMessage(Context arg0, Intent arg1) {
        Log.d("onMessage", String.valueOf(arg1));
    }

    @Override
    protected void onRegistered(Context arg0, String arg1) {
        Log.d("onRegistered", arg1);
    }

    @Override
    protected void onUnregistered(Context arg0, String arg1) {
        Log.d("onUnregistered", arg1);
    }
}

I attempt to register with the following in the onCreate method of my main class:

GCMRegistrar.checkDevice(this);
GCMRegistrar.checkManifest(this);

final String regId = GCMRegistrar.getRegistrationId(this);
if (regId.equals("")) {
    GCMRegistrar.register(this, SENDER_ID);
} else {
    Log.d(TAG, "Already registered");
}

UPDATE I have tried Raz's suggestion and I got the following error:

07-03 12:07:40.459: W/dalvikvm(341): threadid=1: thread exiting with uncaught exception (group=0x4001d800)
07-03 12:07:40.508: E/AndroidRuntime(341): FATAL EXCEPTION: main
07-03 12:07:40.508: E/AndroidRuntime(341): java.lang.RuntimeException: Unable to instantiate service package.gcm2.GCMIntentService: java.lang.InstantiationException: package.gcm2.GCMIntentService
07-03 12:07:40.508: E/AndroidRuntime(341):  at android.app.ActivityThread.handleCreateService(ActivityThread.java:2943)
07-03 12:07:40.508: E/AndroidRuntime(341):  at android.app.ActivityThread.access$3300(ActivityThread.java:125)
07-03 12:07:40.508: E/AndroidRuntime(341):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2087)
07-03 12:07:40.508: E/AndroidRuntime(341):  at android.os.Handler.dispatchMessage(Handler.java:99)
07-03 12:07:40.508: E/AndroidRuntime(341):  at android.os.Looper.loop(Looper.java:123)
07-03 12:07:40.508: E/AndroidRuntime(341):  at android.app.ActivityThread.main(ActivityThread.java:4627)
07-03 12:07:40.508: E/AndroidRuntime(341):  at java.lang.reflect.Method.invokeNative(Native Method)
07-03 12:07:40.508: E/AndroidRuntime(341):  at java.lang.reflect.Method.invoke(Method.java:521)
07-03 12:07:40.508: E/AndroidRuntime(341):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
07-03 12:07:40.508: E/AndroidRuntime(341):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
07-03 12:07:40.508: E/AndroidRuntime(341):  at dalvik.system.NativeStart.main(Native Method)
07-03 12:07:40.508: E/AndroidRuntime(341): Caused by: java.lang.InstantiationException: package.gcm2.GCMIntentService
07-03 12:07:40.508: E/AndroidRuntime(341):  at java.lang.Class.newInstanceImpl(Native Method)
07-03 12:07:40.508: E/AndroidRuntime(341):  at java.lang.Class.newInstance(Class.java:1429)
07-03 12:07:40.508: E/AndroidRuntime(341):  at android.app.ActivityThread.handleCreateService(ActivityThread.java:2940)
07-03 12:07:40.508: E/AndroidRuntime(341):  ... 10 more
07-03 12:08:34.560: I/Process(341): Sending signal. PID: 341 SIG: 9
Community
  • 1
  • 1
eimmer
  • 319
  • 1
  • 3
  • 13

3 Answers3

41

In your manifest try this:

<receiver
        android:name="com.google.android.gcm.GCMBroadcastReceiver"
        android:permission="com.google.android.c2dm.permission.SEND" >
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />

            <category android:name="eimmer.liav.elucidate.gcm2" />
        </intent-filter>
    </receiver>

The category name needs to be your application package.

If the service is in the same package name the leave it like you did else change it to your real package instead of .GCMIntentService but then you would also need to extend and override the GCMBroadcastReceiver.

If your package is not eimmer.liav.elucidate.gcm2.GCMIntentService then you must extend GCMBroadcastReceiver and override the function getGCMIntentServiceClassName(). In that function return the real package and class in string example: eimmer.liav.example.GCMIntentService.

Also don't forget to change the receiver name to the new one. example:

 <receiver
        android:name="eimmer.liav.example.MyGCMBroadcastReceiver"
        android:permission="com.google.android.c2dm.permission.SEND" >
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />

            <category android:name="eimmer.liav.elucidate.gcm2" />
        </intent-filter>
    </receiver>

Further more change your service name to:

<service android:name="eimmer.liav.example.GCMIntentService" 
            android:enabled="true"/>

One other thing according to Google you need to change your constructor to default one and send some string like this:

public GCMIntentService() {
        super("Test");
    }

The string is not really important as far as I know.

Have fun.

Anas Azeem
  • 2,820
  • 3
  • 24
  • 37
Raz
  • 8,918
  • 3
  • 27
  • 40
  • I did try that, but then I get an error "unable to instantiate the service..." (I revised my original post to include the full trace. – eimmer Jul 04 '12 at 16:47
  • Are you not suppose to extend GCMBaseIntentService? – eimmer Jul 04 '12 at 17:19
  • 1
    The default constructor with the misc. String was the piece I seemed to miss... Thank you!!! – eimmer Jul 06 '12 at 05:21
  • I implemented the above solution and found a problem when the server is not available (GCM error = SERVICE_NOT_AVAILABLE). My GCMIntentService::onError was never notified of the error, and I think it is because of error: "W/ActivityManager(351): Unable to start service Intent { act=com.google.android.gcm.intent.RETRY flg=0x14 cmp=my.package.name/.GCMIntentService (has extras) }: not found". I.E. In spite of above solution GCM code is still looking for my GCMIntentService in app package. (Tried adding "com.google.android.gcm.intent.RETRY" action to my custom GCM receiver in manifest.) – Tom Oct 01 '12 at 17:18
  • The official tutorial led me to believe that `GCMIntentService` was to implement `GCMBroadcastReceiver`. With that, I was getting errors. It was fixed when I switched it to `GCMBaseIntentService`. – dtbarne Oct 03 '12 at 20:07
  • What I found useful is to return the string by using `return GCMIntentService.class.getName();`, This way it is more robust against refactoring. Even though not in the Android manifest file. – Konrad Reiche Mar 05 '13 at 23:16
5

What was wrong in your code is in your GCMIntentService, you need to override the default constructor with NO arguments. To pass the senderID still, do it like this:

public static final String SENDER_ID = "sender-id-here";

public GCMIntentService() 
{
    super(SENDER_ID);
}

This will most likely be a common issue for people because eclipse auto-generates a protected constructor with the String as a parameter.

Bart
  • 19,692
  • 7
  • 68
  • 77
boltup_im_coding
  • 6,345
  • 6
  • 40
  • 52
  • 1
    It would be nice if com.google.android.gcm.GCMBroadcastReceiver would pass a context when instantiating GCMIntentService instead of using the no-arg constructor so it could look up the sender ID from resources instead of having to hard-code it into the class. – jph Jul 09 '12 at 22:49
  • 3
    @user190758 you actually don't have to hardcode it. In your constructor, just call the no-arg super(). You then **have to** override getSenderIds(Context context) in your GCMService, which allows you to fetch the senderId(s) from a resource. – Mopper Aug 08 '12 at 11:40
5

This intent service will be called by the GCMBroadcastReceiver (which is is provided by GCM library), as shown in the next step. It must be a subclass of com.google.android.gcm.GCMBaseIntentService, must contain a public constructor, and should be named my_app_package.GCMIntentService (unless you use a subclass of GCMBroadcastReceiver that overrides the method used to name the service).

You should just override getGCMIntentServiceClassName method of GCMBroadcastReceiver class and set your custom IntentService class name. Then fix the AndroidManifest.xml.

More details and sample code you can find here.

dexxtr
  • 478
  • 1
  • 5
  • 8