2

It's just something that puzzles me. Is it possible to use the current instance of the class within the constructor?

I've created a BroadcastReceiver that registers itself with the context within the constructor of the BroadcastReceiver. In addition it will unregister again. Is this good style?

Here's my example:

public class MyBroadcastReceiver extends BroadcastReceiver {

    protected Context                       context;
    protected MyOnBroadcastReceivedListener listener;
    protected int                           receiverId;
    protected String                        receiverTag;

    public MyBroadcastReceiver(int receiverId, Context context, MyOnBroadcastReceivedListener listener, String receiverTag) {
        super();

        this.context = context;
        this.listener = listener;
        this.receiverId = receiverId;
        this.receiverTag = receiverTag;

        IntentFilter intentFilter = new IntentFilter(receiverTag);

        context.registerReceiver(this, intentFilter);   // <--- Look at the use of this here
    }

    public void detach() {
        if (context != null) {
            context.unregisterReceiver(this);   // <--- Look at the use of this 
        }
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        // ...
        if (listener != null) {
            listener.onBroadcastReceived(receiverId, "Bla", "Blub");
        }
    }
}
dcernahoschi
  • 14,968
  • 5
  • 37
  • 59
Harald Wilhelm
  • 6,656
  • 11
  • 67
  • 85
  • This would be much clearer in, for example, Objective-C which has two different methods for "construction", i.e. alloc (for object creation) and init (in which it is obvious you can use 'this'). – Andreas Tasoulas Sep 01 '12 at 08:58

4 Answers4

1

If you refer to using this in constructor code, then yes - it is perfectly valid, otherwise constructor would not be really able to construct to much within own instance. I'd however suggest following common practice and prefix your class members (most commonly used prefix is 'm') which helps avoid problems which are sometimes hard to debug. So instead of:

protected Context                       context;
protected MyOnBroadcastReceivedListener listener;

you would have:

protected Context                       mContext;
protected MyOnBroadcastReceivedListener mListener;
Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
  • Thanks. The 'm' thing ;-) I saw it in the rules for Android contributors. But I don't contribute for Android itself - I'm just a poor App developer ;-) I hate to put 'm' in front of meaningful names - it's just a personal un-preference. Thanks anyway for the tip. – Harald Wilhelm Sep 01 '12 at 09:26
  • Rethink your approach - it is beneficial, even you dislike at start, trust me :) It is still meaningful name but 'm' prefix just instantly tells its class member, not local variable, not to mention it is now hard to assign value to the wrong "target" and you do not need to use `this` like in your example code. – Marcin Orlowski Sep 01 '12 at 09:33
  • What's wrong with 'this'. A Context is a context not a mContext ;-) – Harald Wilhelm Sep 01 '12 at 09:50
  • Imagine complex code with many local variables of common name in a class where you got also many members of common names and you do not handle them all with setters/getters yet your methods often set/read these members. How easy is to forget `this` and set/get local variable instead of member that way? But do as you like. I switched to that naming convention and it works for me. – Marcin Orlowski Sep 01 '12 at 09:53
  • I would give them meaningful names - not mContext. Perhaps serviceContext/intentContext/... would be more reasonable. But 'm'? What's 'm'? Did Michael invent this ;-) – Harald Wilhelm Sep 01 '12 at 11:49
  • You do not get it - you still have serviceContext local variable. Well, i guess 'm' stands for 'member'. In fact I use 'm' because others use it to and it often helps to follow some sort of standards. I do not use 'm' prefix for anything but members so this works for me. – Marcin Orlowski Sep 01 '12 at 13:01
1

Yes, no trouble at all.

Inside the constructor, the object has been created but still no reference has been returned to the rest of the java code. You can use this without worries.

Anyway, in some frameworks where some attributes may be initialized automatic (Context Dependent Injection, CDI), it is not possible to fully initialize the class in the constructor (because such attributes are still not available and may be needed). These frameworks rely in that you mark a method as @PostConstruct; after all attributes are set that method will be called (just so you know what it means when you find it).

SJuan76
  • 24,532
  • 6
  • 47
  • 87
  • @Harald Wilhelm This is a really bad thing to do. This way you can leak references of a not yet constructed object to another thread. Take a look at java tutorial about concurrency: http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html – dcernahoschi Sep 06 '12 at 17:32
0

You can do this, but is not a good style. Passing this from inside a class constructor is dangerous as the current, still constructing object might not be fully intialized.

For example, you might one day add a new int field to the MyBroadcastReceiver, but overlook that you have the statement context.registerReceiver(this, intentFilter); and add the intialization of the new field at the end of the constructor:

public MyBroadcastReceiver(int receiverId, Context context, MyOnBroadcastReceivedListener listener, String receiverTag) {
    super();

    this.context = context;
    this.listener = listener;
    this.receiverId = receiverId;
    this.receiverTag = receiverTag;

    IntentFilter intentFilter = new IntentFilter(receiverTag);

    context.registerReceiver(this, intentFilter);   // <--- Look at the use of this here

    this.newField = 1;
}

Now, you might expect that in the Context.registerReceiver method the newField to be 1 as it initialized in the MyBroadcastReceiver constructor. But you will get the value 0.

See also the following SO question for more information and more potential problems that could appear: Passing "this" in java constructor

Community
  • 1
  • 1
dcernahoschi
  • 14,968
  • 5
  • 37
  • 59
-1

Yes it works. I tried a simple test case. and it works. :

public class Test {
    private int variable;
    private Test2 test2;

    public Test(int variable, Test2 test2) {
        this.variable = variable;
        this.test2 = test2;
        test2.printTest(this);
    }

    public int getVariable() {
        return variable;
    }

    public static void main(String[] args) {
        Test test = new Test(111111,new Test2());
    }
}
class Test2{

    Test2() {
    }

    public void printTest(Test test){
        System.out.println(test.getVariable());
    }
}

And it works like a charm