2

I am making a simple reminder app. I am getting a null pointer exception when the reminder goes off.

Here the key info from Logcat: Caused by: java.lang.NullPointerException at com.joshbgold.move.AlarmReceiver.onReceive(AlarmReceiver.java:34)

Evidently I am not initializing AlarmActivity inst properly. I know this is probably a simple fix, thanks for your patience with a newer Java programmer.

AlarmReceiver.java:

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.media.MediaPlayer;
import android.support.v4.content.WakefulBroadcastReceiver;

/**
 * Created by JoshG on 7/6/2015.
 */

public class AlarmReceiver extends WakefulBroadcastReceiver {

    @Override
    public void onReceive(final Context context, Intent intent) {
        //MediaPlayer is used to play an mp3 file
        final MediaPlayer mediaPlayer = MediaPlayer.create(context, R.drawable.om_mani_short);

        mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

            @Override
            public void onCompletion(MediaPlayer mediaplayer) {
                mediaplayer.stop();
                mediaplayer.release();
            }
        });

        mediaPlayer.start();

        //this will update the UI with message
        AlarmActivity inst = AlarmActivity.instance();
        inst.setAlarmText("stretch");

        //this will send a notification message
        ComponentName comp = new ComponentName(context.getPackageName(),
                AlarmService.class.getName());
        startWakefulService(context, (intent.setComponent(comp)));
        setResultCode(Activity.RESULT_OK);
    }

}

AlarmActivity.java:

package com.joshbgold.move;

import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.ToggleButton;

import java.util.Calendar;

/**
 * Created by JoshG on 7/6/2015.
 */
public class AlarmActivity extends Activity {

    AlarmManager alarmManager;
    private PendingIntent pendingIntent;
    private TimePicker alarmTimePicker;
    private static AlarmActivity inst;
    private TextView alarmTextView;

    public static AlarmActivity instance() {
        return inst;
    }

    @Override
    public void onStart() {
        super.onStart();
        inst = this;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        alarmTimePicker = (TimePicker) findViewById(R.id.alarmTimePicker);
        alarmTextView = (TextView) findViewById(R.id.alarmText);
        ToggleButton alarmToggle = (ToggleButton) findViewById(R.id.alarmToggle);
        final Button exitButton = (Button) findViewById(R.id.exitButton);
        alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);

        final MediaPlayer mediaPlayer = MediaPlayer.create(this, R.drawable.om_mani_short);

      mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

            @Override
            public void onCompletion(MediaPlayer mediaplayer) {
                mediaplayer.stop();
                mediaplayer.release();
            }
        });

        mediaPlayer.start();

        View.OnClickListener quitApp = new View.OnClickListener() {  //this block stops music when exiting
            @Override
            public void onClick(View view) {

                if (mediaPlayer != null) try {
                    if (mediaPlayer.isPlaying()) {
                        mediaPlayer.stop();
                        mediaPlayer.release();
                    }
                } catch (Exception e) {
                    Log.d("Alarm Activity", e.toString());
                }

                finish();
            }
        };

        exitButton.setOnClickListener(quitApp);
    }

    public void onToggleClicked(View view) {
        if (((ToggleButton) view).isChecked()) {
            Log.d("MyActivity", "Alarm On");
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.HOUR_OF_DAY, alarmTimePicker.getCurrentHour());
            calendar.set(Calendar.MINUTE, alarmTimePicker.getCurrentMinute());
            Intent myIntent = new Intent(AlarmActivity.this, AlarmReceiver.class);
            pendingIntent = PendingIntent.getBroadcast(AlarmActivity.this, 0, myIntent, 0);
            alarmManager.set(AlarmManager.RTC, calendar.getTimeInMillis(), pendingIntent);
        } else {
            alarmManager.cancel(pendingIntent);
            setAlarmText("Alarm Off");
            Log.d("MyActivity", "Alarm Off");
        }
    }

    public void setAlarmText(String alarmText) {
        alarmTextView.setText(alarmText);
    }
}

Alarm Service.java

package com.joshbgold.move;

import android.app.IntentService;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

/**
 * Created by JoshG on 7/6/2015.
 */
public class AlarmService extends IntentService {
    private NotificationManager alarmNotificationManager;

    public AlarmService() {
        super("AlarmService");
    }

    @Override
    public void onHandleIntent(Intent intent) {
        sendNotification("stretch");
    }

    private void sendNotification(String msg) {
        Log.d("AlarmService", "Preparing to send notification...: " + msg);
        alarmNotificationManager = (NotificationManager) this
                .getSystemService(Context.NOTIFICATION_SERVICE);

        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
                new Intent(this, AlarmActivity.class), 0);

        NotificationCompat.Builder alarmNotificationBuilder = new NotificationCompat.Builder(
                this).setContentTitle("Reminder").setSmallIcon(R.mipmap.ic_launcher)
                .setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
                .setContentText(msg);


        alarmNotificationBuilder.setContentIntent(contentIntent);
        alarmNotificationManager.notify(1, alarmNotificationBuilder.build());
        Log.d("AlarmService", "Notification sent.");
    }
}

Here is the contents of Logcat. I have it set to Log Level of Error:

07-07 18:53:13.119  13065-13065/com.joshbgold.move E/﹕ mali: REVISION=Linux-r3p2-01rel2 BUILD_DATE=Mon Nov 18 21:41:36 KST 2013
07-07 19:00:11.569  16746-16746/com.joshbgold.move E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.RuntimeException: Unable to start receiver com.joshbgold.move.AlarmReceiver: java.lang.NullPointerException
            at android.app.ActivityThread.handleReceiver(ActivityThread.java:2469)
            at android.app.ActivityThread.access$1600(ActivityThread.java:158)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1372)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:176)
            at android.app.ActivityThread.main(ActivityThread.java:5365)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.NullPointerException
            at com.joshbgold.move.AlarmReceiver.onReceive(AlarmReceiver.java:34)
            at android.app.ActivityThread.handleReceiver(ActivityThread.java:2462)
            at android.app.ActivityThread.access$1600(ActivityThread.java:158)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1372)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:176)
            at android.app.ActivityThread.main(ActivityThread.java:5365)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1102)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869)
            at dalvik.system.NativeStart.main(Native Method)
joshgoldeneagle
  • 4,616
  • 2
  • 23
  • 30

3 Answers3

1
//this will update the UI with message
AlarmActivity inst = AlarmActivity.instance();
inst.setAlarmText("stretch");

inst is null. You should check AlarmActivity.instance()

public static AlarmActivity instance() {
    if (inst == null) {
        // Do something such as inst = ...
    }

    return inst;
}
codeaholicguy
  • 1,671
  • 1
  • 11
  • 18
  • I moved these two lines below to the top of OnReceive method for a test, and the error follows these lines. AlarmActivity inst = AlarmActivity.instance(); inst.setAlarmText("stretch"); So it is unlikely the exception has anything to do with context.getPackageName(). – joshgoldeneagle Jul 08 '15 at 03:06
  • @joshgoldeneagleos ok after you post your code I understood. The problem come from AlarmActivity.instance(). I will update my answer. – codeaholicguy Jul 08 '15 at 03:12
  • Ok, can I do the following to supply the inst activity? inst = setContentView(R.layout.SomeActivityOfMyChoosing); – joshgoldeneagle Jul 08 '15 at 03:24
  • yes, you should create inst when it null, like you did in onCreate() – codeaholicguy Jul 08 '15 at 03:30
1

If this is the class, line 34 is

 inst.setAlarmText("stretch");

which points to the line above it not getting an actual activity

AlarmActivity inst = AlarmActivity.instance();

Check your AlarmActivity class to make sure inst is not null when it is created with the instance() method.

Can you post your AlarmActivity class to see how you are creating/fetching your instance?

randal4
  • 590
  • 4
  • 16
  • Hello randal4, just posted AlarmActivity class. Thx. I am looking at it too and maybe will see the problem here shortly. – joshgoldeneagle Jul 08 '15 at 02:36
  • Have you tried putting the inst = this in the onCreate method? This site does something similar but they make the textviews static and then create static getters for them. Then call them from the onReceive method. Have you tried putting the inst = this in the onCreate method? This site does something similar but they make the textviews static and then create static getters for them. Then call them from the onReceive method. http://www.concretepage.com/android/android-alarm-clock-tutorial-to-schedule-and-cancel-alarmmanager-pendingintent-and-wakefulbroadcastreceiver-example – randal4 Jul 08 '15 at 03:02
  • I just added inst = this; in the OnCreate method and that did not appear to be the solution, as I got the same exception when the alarm fires. Posting the only other class file for everyone to see, then I am going to take a break until tomorrow. A good night's sleep, and the solution often just pops into my brain. I think we are close. – joshgoldeneagle Jul 08 '15 at 03:18
  • After messing with it a bit tonight I discovered if you have android:process="remote" in your definition in your AndroidManifest.xml file, it will spin up a new process for your receiver. This will cause your static variables to not be visible in that process. See this post for more info http://stackoverflow.com/a/4413816/1410671 Once I removed that, the null pointer went away. – randal4 Jul 09 '15 at 02:27
  • randal4, how do you feel about the original plan of using an instance of AlarmActivity versus the new plan of spinning up a new activity (see my answer posted on this page). – joshgoldeneagle Jul 09 '15 at 16:56
0

I took a sharp right turn, and did a different implementation when the reminder/alarm goes off. While I am doing something a little different then originally intended, the above answers provided led me in the correct direction.

Here is what I am using for AlarmReceiver.java:

    package com.joshbgold.move;    

    import android.content.Context;
    import android.content.Intent;
    import android.support.v4.content.WakefulBroadcastReceiver;

    public class AlarmReceiver extends WakefulBroadcastReceiver {

        @Override
        public void onReceive(final Context context, Intent intent) {
            //this will change to new activity for Reminder(s) at the appropriate time
            Intent myIntent = new Intent();
            myIntent.setClassName("com.joshbgold.move", "com.joshbgold.move.ReminderActivity");
            myIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(myIntent);
     }
    }
joshgoldeneagle
  • 4,616
  • 2
  • 23
  • 30