Search code examples
androidandroid-fragmentsandroid-intentandroid-notificationsflags

Android app crash.. intent flag?


My app has been getting some crashes lately, and I'm wondering if it could be due to the flags on the intents.

When the crash happens, the app is closed I believe, during a rest timer. A fragment is opened, then the user can click start, which starts a 90 second countdown timer. The user gets a notification when the timer ends, which when clicked should bring the user back to the open fragment. The error doesn't happen very often, I can't recreate it every time.

Here is the stacktrace:

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Context.getPackageName()' on a null object reference
at android.content.ComponentName.<init>(ComponentName.java:77)
at android.content.Intent.<init>(Intent.java:4913)
at com.bestworkouts.sheikoworkout.Workouts.Week1Mon.showNotification(Week1Mon.java:171)
at com.bestworkouts.sheikoworkout.Workouts.Week1Mon$1.onFinish(Week1Mon.java:147)
at android.os.CountDownTimer$1.handleMessage(CountDownTimer.java:127)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:6938)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1404)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1199)

and here is the notification where the error is(it says the error is at Intent intent = new Intent(getActivity(), MyWorkout.class):

public void showNotification() {
    NotificationCompat.Builder builder = new NotificationCompat.Builder(getContext());
    builder.setSmallIcon(R.drawable.sheikoicon);
    builder.setContentTitle("Sheiko Rest Timer");
    builder.setContentText("Rest timer is up, start your set!");
    builder.setDefaults(Notification.DEFAULT_SOUND|Notification.DEFAULT_VIBRATE);
    builder.setAutoCancel(true);
    Intent intent = new Intent(getActivity(), MyWorkout.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    TaskStackBuilder stackBuilder = TaskStackBuilder.create(getContext());
    stackBuilder.addParentStack(MyWorkout.class);
    stackBuilder.addNextIntent(intent);
    PendingIntent pendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
    builder.setContentIntent(pendingIntent);
    NotificationManager NM = (NotificationManager) getActivity().getSystemService(Context.NOTIFICATION_SERVICE);
    NM.notify(0, builder.build());
}

Where I start the countdown timer and call showNotification:

private void start() {
    cancel();
    mCountDownTimer = new CountDownTimer(90000, 1000) {
        @Override
        public void onTick(long millisUntilFinished) {
            txtViewRest.setText(millisUntilFinished / 1000 + " Secs");
        }

        @Override
        public void onFinish() {
            txtViewRest.setText("Start!");
            showNotification();
        }
    }.start();
}

I'm wondering if it has something to do with my FLAG_ACTIVITY_CLEAR_TOP?

Thanks for help!


Solution

  • Since your code is running on another thread, if by the time the CountDownTimer is finished the Fragment has been closed for any reason, both getActivity() and getContext() will return null.

    You should save your context in the Fragment's onCreate:

    private Context context;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        context= getContext();
    
        // Your code here
    
    }
    

    Then use it in inside your showNotification() method:

    public void showNotification() {
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
        builder.setSmallIcon(R.drawable.sheikoicon);
        builder.setContentTitle("Sheiko Rest Timer");
        builder.setContentText("Rest timer is up, start your set!");
        builder.setDefaults(Notification.DEFAULT_SOUND|Notification.DEFAULT_VIBRATE);
        builder.setAutoCancel(true);
        Intent intent = new Intent(context, MyWorkout.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
        stackBuilder.addParentStack(MyWorkout.class);
        stackBuilder.addNextIntent(intent);
        PendingIntent pendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
        builder.setContentIntent(pendingIntent);
        NotificationManager NM = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        NM.notify(0, builder.build());
    }