Search code examples
javaandroidandroid-activitysingletonobserver-pattern

Observer update() causing a NullPointerException


I'm trying to use the Observer pattern to notify the observer(s) of a BroadcastReceiver that a new message has been received. When the update() method in the activity is called, the fields in the activity should be updated so that the message can be displayed on the screen. However, I keep getting a NullPointerException at that point.

Here is an excerpt from the related log:

04-15 13:03:21.252  31107-31107/com.example.sam.yak E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.sam.yak, PID: 31107
java.lang.RuntimeException: Unable to start receiver com.example.sam.yak.Receive: java.lang.NullPointerException
        at android.app.ActivityThread.handleReceiver(ActivityThread.java:2698)
        at android.app.ActivityThread.access$1700(ActivityThread.java:153)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1434)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:157)
        at android.app.ActivityThread.main(ActivityThread.java:5633)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:515)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:896)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:712)
        at dalvik.system.NativeStart.main(Native Method)
 Caused by: java.lang.NullPointerException
        at com.example.sam.yak.SendActivity.update(SendActivity.java:94)
        at com.example.sam.yak.Receive.notifyObservers(Receive.java:82)
        at com.example.sam.yak.Receive.onReceive(Receive.java:53)
        at android.app.ActivityThread.handleReceiver(ActivityThread.java:2687) at android.app.ActivityThread.access$1700(ActivityThread.java:153) at       android.app.ActivityThread$H.handleMessage(ActivityThread.java:1434) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:157) at android.app.ActivityThread.main(ActivityThread.java:5633) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:896) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:712) at dalvik.system.NativeStart.main(Native Method)

The relevant code for SendActivity (the observer) is as follows:

public class SendActivity extends Activity implements Observer {

private static SendActivity send;
String message;
String sender;
Receive receive;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_send);
    sender = "";
    message = "";
    receive = Receive.getInstance();
}

public static synchronized SendActivity getInstance() {
    if (send == null)
        send = new SendActivity();
    return send;
}


@Override
public void update() {
    message = receive.getMessage();
    sender = receive.getSenderNumber();
    retrieve();
}

also, relevant code for Receive (the observable):

public class Receive extends BroadcastReceiver {

public static Receive receive;
String sender = "";
String message = "";
List<Observer> observers = new ArrayList<>();
SendActivity send = SendActivity.getInstance();

public Receive() {}

public static synchronized Receive getInstance() {
    if (receive == null)
        receive = new Receive();
    return receive;
}

/**
 *
 * @param context
 * @param intent
 */
@Override
public void onReceive(Context context,Intent intent) {
    //newMsg = false;
    addObserver(send);
    Bundle bundle = intent.getExtras();
    if(!(bundle == null)) {
        Object[] pdus = (Object[])bundle.get("pdus");
        SmsMessage[] msgs = new SmsMessage[pdus.length];
        for (int i = 0; i < msgs.length; i++) {
            msgs[i] = SmsMessage.createFromPdu((byte[])pdus[i]);
            //newMsg = true;
            setSender(msgs[i].getOriginatingAddress());
            setMessage(msgs[i].getMessageBody());
            Toast.makeText(context,msgs[i].getMessageBody(),Toast.LENGTH_SHORT).show();
            notifyObservers();
        }
    }
}

public void setSender(String s) {
    sender = s;
}

public void setMessage(String s) {
    message = s;
}

public String getSenderNumber() {
    return sender;
}

public String getMessage() {
    return message;
}

public void addObserver(Observer o) {
    if((o != null) && (!observers.contains(o))){
        observers.add(o);
    }
}

public void notifyObservers() {
    for(Observer l : observers) {
        l.update();
    }
}
}

Any feedback & recommendations greatly appreciated.


Solution

  • I can't be sure but I think your usage of singletons is problematic. Suppose SendActivity is created first. In its onCreate method Receive.getInstance() is called, which in turn calls SendActivity.getInstance() but the SendActivity instance is not ready yet. I don't think your Receive class is ever properly initialized.