21

In my code there is an inner class that extends BroadcastReceiver.

And I have added the following line to the AndroidManifest.xml:

<receiver android:name="OuterClass$InnerClass android:enabled="true"/>

But I am receiving the following error:

unable to instantiate receiver org.example.test.OuterClass$InnerClass

How can I solve this issue ?

Vijay
  • 1,163
  • 8
  • 22
Kunal P.Bharati
  • 949
  • 4
  • 11
  • 19

6 Answers6

33

An (non-static) inner class cannot be instantiated by Android via the AndroidManifest.xml (Android developer documentation on BroadcastReceiver):

You can either dynamically register an instance of this class with Context.registerReceiver() or statically publish an implementation through the tag in your AndroidManifest.xml.

So you can dynamically register the receiver. In my application I wanted to do the same for using Google's Cloud to Device Messaging (C2DM) and my original AndroidManifest.xml contained:

<application...>
    <receiver android:name=".MyC2dmReceiver" android:permission="com.google.android.c2dm.permission.SEND">
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <category android:name="com.example.myapp" />
        </intent-filter>
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
            <category android:name="com.example.myapp" />
        </intent-filter>
    </receiver>
</application>

I removed that receiver section and dynamically registered the receiver as follows:

public class AndroidService extends IntentService
{
    ... 
    @Override
    public int onStartCommand(Intent intent, int flags, int startId)
    {
        IntentFilter filter = new IntentFilter();
        filter.addAction("com.google.android.c2dm.intent.RECEIVE");
        filter.addAction("com.google.android.c2dm.intent.REGISTRATION");
        filter.addCategory("com.example.myapp");
        this.registerReceiver(new MyC2dmReceiver(), filter, "com.google.android.c2dm.permission.SEND", null);
        return super.onStartCommand(intent,flags,startId);
    }

    public class MyC2dmReceiver extends BroadcastReceiver
    {
        ...
    }
}
Bert Regelink
  • 2,696
  • 23
  • 17
  • I have a question about this. What happens to the object of MyC2dmReceiver that was registered after it receives an intent? Does it stay alive and ready to receive another one or does it get available for deletion by the GC and we need to register another instance of it? – Luis Paulo Nov 06 '16 at 11:31
18

The $ notation doesn't denote an inner class, but a static nested class. So there are in theory 2 ways to solve this particular problem:

  1. Denote it as a real inner class, i.e. OuterClass.InnerClass (not sure though if Android will eat that since the instantiation of an inner class is pretty more complex than just doing Class#newInstance().

  2. Declare the class to be a static nested class instead, i.e. add static to class InnerClass {}. This way the OuterClass$InnerClass must be able to create a new instance out of it.

If that doesn't solve the problem, then apparently Android simply doesn't eat it that way. I'd just extract it into its own standalone class then.

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thanx for the answer BalusC :) But in my case I wanna call an Async class which is inner class of my activity using Alarm. Any ideas how to do it? – Kunal P.Bharati Sep 01 '10 at 12:29
  • 1
    I can confirm that it is possible to use static nested class using the Outer$Inner notation; in my case, I'm creating an AppWidgetProvider receiver and the inner class extends the outer class to specify a unique AppWidgetProvider for each sizes. – Lie Ryan Dec 28 '11 at 09:21
7

Could it be that there is just a dot and a closing quote missing? Like

<receiver android:name=".OuterClass$InnerClass" android:enabled="true"/>
DonGru
  • 13,532
  • 8
  • 45
  • 55
4

This is what worked for me:

public class OuterClass {
    public static class InnerStaticClass extends BroadcastReceiver {
        @Override
        public void onReceive(final Context context, final Intent intent) {
            final Location location = (Location) intent.getExtras().get(LocationClient.KEY_LOCATION_CHANGED);
        }
    }
}

AndroidManifest.xml:

    <receiver android:name=".OuterClass$OuterClassConnector$InnerStaticClass" />
Gavriel
  • 18,880
  • 12
  • 68
  • 105
  • What is `OuterClassConnector` here? – Srujan Barai Mar 14 '16 at 08:04
  • I don't find that in my code now, it's been changed in the past 2 years a lot. I think it was generated somehow by android when I implemented GoogleApiClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks interfaces. But now I use a solution with explicit intent class: new Intent(mContext, InnerStaticClass.class); – Gavriel Mar 14 '16 at 08:55
  • Thanks.. this works for me. But i also defined: android:enabled="true" in receiver tag defined in manifest. – Ali Azaz Alam Mar 14 '19 at 18:57
0

I've just met the same problem.

I have a service to communicate with many activities, and I also have a receiver in my service as inner class. when the receiver get message ,it has to call the method of service. so it goes on like this :

1. Service code:

public class XXService extends Service{

     // I want the inner receiver call the methd of XXService,
    // so I have to write this constructor like this.

    private XXService instance;
    public XXService(){instance = this;}
    public XXService getInstance(){
       return instance;
    }
    public void sayHello(){
    }
    public static class XXReceiver extends BroadcastReceiver{

        onReceive(......){
            XXService.getInstance.sayHello();
        } 
   }
}

2. Register receiver in manifest.xml :

<receiver android:name=".XXService$XXReceiver" android:enabled="true"/>
MHSaffari
  • 858
  • 1
  • 16
  • 39
River
  • 228
  • 3
  • 12
  • This seems really impressive to me. May be just what I wanted. I'll try this and revert if it works. – Srujan Barai Mar 14 '16 at 08:10
  • This is working. Thank you. Well I didnt write `android:enable="true"` yet it is working. Any idea? Or that was just for being on the safer side? – Srujan Barai Mar 14 '16 at 09:22
  • `Non-static method 'getInstance()' cannot be referenced from a static context`. Both `instance` and `getInstance()` need to be static. But then you may get: `Do not place Android context classes in static fields; this is a memory leak` – Luis A. Florit Jun 29 '22 at 20:14
0

you dont need to use $... If you get warning for a class which is not actually an inner class, it's because you are using uppercase characters in your package name, which is not conventional.

I tried also to change only the first letter of the package name to be lower case, the warning and error disappeared.

MBH
  • 16,271
  • 19
  • 99
  • 149