5

I am trying to display notification in an interval using Broadcast Receiver and timer to display. It works when the app is running but did not work when the app is killed.

Receiver looks like

public class MyReceiver  extends BroadcastReceiver {
    int j;
      public void onReceive(final Context context, Intent intent) {

        // Vibrate the mobile phone
        //Declare the timer
        Timer t = new Timer();

//Set the schedule function and rate
        t.schedule(new TimerTask() {

                       @Override
                       public void run() {
                           Log.d("ME", "Notification started");

                           NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context);
                           mBuilder.setSmallIcon(R.drawable.ddc);
                           mBuilder.setContentTitle("My notification");
                           mBuilder.setDefaults(Notification.DEFAULT_SOUND);
                           mBuilder.setContentText("Hello World!");

                           NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
                           mNotificationManager.notify(j++, mBuilder.build());

                       }

                   },
                0,
                30000);
    }
}

AndroidManifest.xml Looks like

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.background.pushnotification">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <receiver  android:name="MyReceiver"
            android:enabled="true"
            android:exported="true"
            >
            <intent-filter>
                <action android:name="com.background.myreceiver" />
                <action android:name="android.intent.action.PHONE_STATE" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

It only displays notification in an interval when app is running. It is not displaying notification when the app is killed. What I am missing?

1 Answers1

3

"when the app is killed" is not a precise statement. I am going to guess that you mean "when you swipe away your app from the overview screen (a.k.a., recent-tasks list)".

Once onReceive() returns, if you do not have an activity in the foreground and you do not have a running service, your process importance will drop to what the documentation refers to as a "cached process". Your process is eligible to be terminated at any point. Once your process is terminated, your Timer goes away. Hence, your code as written will be unreliable, as your process might be terminated within your 30-second window.

Other possibilities include:

  • You are doing something else for "when the app is killed" that behaves like "Force Stop" does on your app's screen in Settings. Normally, that "Force Stop" button is the only way to force-stop an app, but occasionally device manufacturers do something stupid and make force-stop something that happens from other things (e.g., a device-supplied "application manager"). Once your app is force-stopped, your code will never run again, until the user launches your app from the home screen launcher icon or something else on the device uses an explicit Intent to start one of your components.

  • If the device falls asleep, your Timer will not be invoked until the device wakes up again.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • By "when the app is killed" I mean removing it from recent task list. Is there a way to run the Timer ( Scheduler). so, that notification pops up in the status bar or is there any other way to do so ? – Kabindra Simkhada Jan 31 '17 at 04:46
  • 2
    @KabindraSimkhada: Use `AlarmManager` or `JobScheduler`. – CommonsWare Jan 31 '17 at 11:39
  • The registered broadcast should work even if the process is killed? I have seen in some custom firmware like ColorOS 5.1.1 (Lollipop) this isn't the case. – Muhammad Babar Jul 19 '18 at 07:31
  • 2
    @MuhammadBabar: Process termination does not affect manifest-registered receivers -- they should still receive broadcasts. "Force stop" affects manifest-registered receivers, and manifest-registered receivers generally do not work on Android 8.0+. If the ColorOS developers did something else, that is unfortunate, emphasizing that ColorOS is a fork of Android and will behave differently. – CommonsWare Jul 19 '18 at 10:56
  • @CommonsWare This may be a bit irrelevant, but can we execute a code when the broadcast receiver is being terminated just like we have onDestroy() for an activity? – Samudra Ganguly Feb 13 '22 at 08:03
  • @SamudraGanguly: Not in the same way. For a manifest-registered receiver, the receiver object instance lasts for just one `onReceive()` call before it is "terminated", so you would put your cleanup logic at the end of `onReceive()`. For a receiver registered via `registerReceiver()`, you can do your cleanup work at the point of `unregisterReceiver()`. – CommonsWare Feb 13 '22 at 12:24
  • @CommonsWare Suppose I have used an asynchronous code (for example a Firebase value event listener). How can I make the broadcast receiver wait till executing onDataChanged() or onCanceled() if it is manifest-registered? – Samudra Ganguly Feb 13 '22 at 18:23
  • @SamudraGanguly: You cannot do that. A broadcast receiver should not be performing its own I/O, such as talking to Firebase. Instead, have the receiver delegate that work to something else designed for that role, such as `WorkManager`. – CommonsWare Feb 13 '22 at 18:33
  • @CommonsWare if we want to read a data from Firebase at a certain time everyday (say 14:00), which is a better option - AlarmManager or WorkManager? – Samudra Ganguly Feb 13 '22 at 18:53