Android - AlarmManager is not working after app is closed

Viewed 6270

I am using AlarmManager to call a function at a certain time. It is working successfully in Genymotion Emulator but not in a real device like Redmi, Honor, etc. Here is the Code.

     Intent intent = new Intent(CreateContact.this, DeleteContactReceiver.class);
     intent.putExtra("name", name.getText().toString());
     intent.putExtra("phone", phoneNumber.getText().toString());
     PendingIntent pendingIntent = PendingIntent.getBroadcast(
                                getApplicationContext(), (int) System.currentTimeMillis(), intent, 0);
    AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
    alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
                                + (selected * 60000), pendingIntent);

The min SDK version is 21.

EDIT: I tried to use setAndAllowWhileIdle but it still won't work.

Any Suggestions?

5 Answers

Use instead the androidx WorkManager library, is the replacement for all scheduling services.

The WorkManager API is a suitable and recommended replacement for all previous Android background scheduling APIs

https://developer.android.com/topic/libraries/architecture/workmanager

What the WorkManager does is to wrap all the existing scheduling services, and use the most appropriate one according to what is available, API level, etc., even taking care of compatibility issues and system bugs.

Some tutorials:

https://medium.com/androiddevelopers/introducing-workmanager-2083bcfc4712

https://www.programmersought.com/article/82731596284/

https://medium.com/swlh/periodic-tasks-with-android-workmanager-c901dd9ba7bc

On certain devices (particularly low-end and Chinese manufacturer), apps are not permitted to perform background functions (if the app is not running) unless the user explicitly enables this. This is to prevent rogue apps from using up the battery by performing background activities.

To get around this, you need to manually add your app to the list of "protected apps" or list of apps that "are allowed to run in the background". To add your app to this list, you need to go to the appropriate setting. This is different on different devices, but it is usually found in either the "power management" or "security" settings.

On Honor devices it is found in "Battery Manager->Protected Apps"

For Xiaomi devices, see https://dontkillmyapp.com/xiaomi

I used this function to make a change in my application daily.

Added Broadcast receiver in Manifest.xml

<receiver  android:name=".AlarmReceiver">
    <action android:name="alarm.running"/>
</receiver>

MainActivity.java

public class MainActivity extends AppCompatActivity {
    AlarmManager alarmMgr;
    PendingIntent alarmIntent;
    Context context;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        context=MainActivity.this;

        AlarmReceiver mScreenStateReceiver = new AlarmReceiver();
        IntentFilter screenStateFilter = new IntentFilter();
        screenStateFilter.addAction("alarm.running");
        registerReceiver(mScreenStateReceiver, screenStateFilter);

        alarmMgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(context, AlarmReceiver.class);
        intent.setAction("alarm.running");
        alarmIntent = PendingIntent.getBroadcast(context, 0, intent, 0);

        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(System.currentTimeMillis());
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 36);

// setRepeating() lets you specify a precise custom interval--in this case,
// 1 day
        alarmMgr.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis()/1000,
                AlarmManager.INTERVAL_DAY, alarmIntent);
    }

}

AlarmReceiver.java // A broadcast receiver to show toast for sample

public class AlarmReceiver  extends BroadcastReceiver{
    @Override
    public void onReceive(Context context, Intent intent) {
        switch (intent.getAction()){
            case "alarm.running":
                Toast.makeText(context, "alarm ran", Toast.LENGTH_SHORT).show();
        }
    }
}

Use the method setExactAndAllowWhileIdle() instead of set() for an action to be triggered precisely in a specific time. However, make sure not to use it regularly unless it's a task worth compromising system resources.

Applications are strongly discouraged from using exact alarms unnecessarily as they reduce the OS's ability to minimize battery use.

Read more AlarmManager  |  Android Developers - setExactAndAllowWhileIdle

Beginning with API 19 alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. So, from above 19 you can use setWindow method as stated in official document at here.

Related