简体   繁体   中英

Android, How to get context in C2DMReceiver constructor?

I have a C2DM receiver class that initialises the C2DM sender email in the constructor. The thing is, I need to get the senders email from a resource string and therefore I need to get the context in the constructor for the receiver

The receiver looks like this

public class C2DMReceiver extends C2DMBaseReceiver {

    public C2DMReceiver() {
        super(AppConstants.getC2DMSender(this)); // How do I get the context here?
    }

    @Override
    public void onRegistered(Context context, String registrationId)
            throws java.io.IOException { ...

The relevant code on the C2DMBaseReceiver

public abstract class C2DMBaseReceiver extends IntentService {
...
    private final String senderId;

    /**
     * The C2DMReceiver class must create a no-arg constructor and pass the 
     * sender id to be used for registration.
     */
    public C2DMBaseReceiver(String senderId) {
        // senderId is used as base name for threads, etc.
        super(senderId);
        this.senderId = senderId;
    }
...

It's not really relevant to the question but for background purposes the reason for needing this is that the code is in a library project that is used in many android projects each of which has it's own sender's email address defined in a resource file. The AppConstants class has the job of reading the various resource strings and follows on from my accepted answer for a previous question here Android, Best way to provide app specific constants in a library project?

Finally for completeness the AppConstants.getC2DMSender method looks like this

public static String getC2DMSender(Context c){
    return c.getResources().getString(uk.co.the_prize_quiz.quiz_template.R.string.c2dm_sender);
}

The specific app that users this library has the responsibility of setting the c2dm_sender variable in an xml resource. So in order to get this variable I need the context

<item type="string" name="c2dm_sender" format="string">app_specific_registered_c2dm@email_address</item>

Because this is set in a resource string the specific app can set this value and the template will use it automatically.

Add a singleton class to your library. Have a member to hold the senderid and corresponding getter and setter methods...

public class ClassicSingleton {
   private static ClassicSingleton instance = null;
   private String mSenderId = nulll; // Your data holder

   protected ClassicSingleton() {
      // Exists only to defeat instantiation.
   }

   public static ClassicSingleton getInstance() {
      if(instance == null) {
         instance = new ClassicSingleton();
      }
      return instance;
   }

   /* Setter and Getter for the mAppContext member here */
   public void setSender(String sender) {
       mSenderId = sender;
   }

}

In your app's activity ClassicSingleton.getInstance().setSender("SENDER_ID")

In your C2DM class

public C2DMReceiver() {
    super(ClassicSingleton.getInstance().getSender());
}

Try to have the app's context as the member instead of senderId. Then you can pull any resource you need I guess.. Let me know.

I have come to the conclusion that this can not be done in the way I was attempting. I have temporarily solved my problem by creating a new class in each app that descends from the class in the library project and just overriding the constructor in each app.

It's not an idea solution and kind of defeats the point of having a library but at least I can share most of my code.

C2DMBaseReceiver doesn't actually use the senderId unless it needs to retry a registration request. C2DMBaseReceiver is an object (IntentService) that gets created and destroyed for each operation (register response, message from server, and re-try registration). As long as you set the senderId before you register, you should be fine.

This seems to work:

public class C2DMReceiver extends C2DMBaseReceiver {
    private static String gSenderId = "dummy";

    public C2DMReceiver() {
        super(gSenderId);
    }

    public static void register(Context context, String senderId) {
        gSenderId = senderId;
        C2DMessaging.register(context, senderId);
    }

    ...
}

Since you are creating a library that provides C2DM service, you should consider what @fargath said and incorporate the c2dm.jar functions directly in your library. Then you can customize the interface as needed. In addition, the c2dm.jar provides an indirection to your library code, then your library code provides an equivalent indirection to the app. It is a bit of a waste.

The c2dm.jar code is only three short files. I am writing a library similar to yours and will likely pull the functionality in myself.

//As C2DMReceiver receiver extends Intent service, rather than passing this , call getApplicationConext 

public class C2DMReceiver extends C2DMBaseReceiver {

public C2DMReceiver() {
    Context context = getApplicationContext();
    super(AppConstants.getC2DMSender(context); // This way you can pass context.
}

@Override
public void onRegistered(Context context, String registrationId)
        throws java.io.IOException { ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM