Search code examples
androidandroid-serviceandroid-alarms

alarm manager can't start at exact time in android


I have a sample app and I want to do some stuff in the background. my service working when I set the time for alarm manager at once but it doesn't work next time I set time (change the code and run the app again for the next 2 minutes).

This is my scenario: I set time for starting service and run the app then click on fab and close the app and wait for the toast.

here are some of my classes :

MainActivity.class

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener( view -> { startBackup();});
    }


    private void startBackup() {

        Intent serviceIntent = new Intent(getApplicationContext(), ExampleService.class);
        PendingIntent pintent = PendingIntent.getService(getApplicationContext(), 123, serviceIntent, 0);


            Calendar cal = initCalendar(14, 36, 0);
            AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

            if (Build.VERSION.SDK_INT >= 23) {
                alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pintent);
            } else if (Build.VERSION.SDK_INT >= 19) {
                alarm.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pintent);
            } else {
                alarm.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pintent);
            }pintent);

        }


    private Calendar initCalendar(int hour, int minute, int second) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);

        return calendar;
    }
}

ExampleService.class

public class ExampleService extends Service {


    @Override
    public void onCreate() {
        super.onCreate();
        Toast.makeText(this, "service create service", Toast.LENGTH_LONG).show();

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Toast.makeText(this, "Service Service you ", Toast.LENGTH_LONG).show();
        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

Manifest.xml

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        tools:ignore="GoogleAppIndexingWarning">
        <activity
            android:name=".MainActivity"
            android:label="service test"
            android:theme="@style/AppTheme.NoActionBar">

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <service android:name=".ExampleService"
            android:enabled="true"
            android:exported="true"
            />
    </application>

</manifest>

Solution

  • after lots of researches, I finally found API 26 added a new method for pending intent called getForeGroundService()

    so the code should look like this :

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            FloatingActionButton fab = findViewById(R.id.fab);
            fab.setOnClickListener( view ->  startBackup());
        }
    
    
        private void startBackup() {
    
            Intent serviceIntent = new Intent(getApplicationContext(), ExampleService.class);
    
    
                Calendar cal = initCalendar(10, 0, 0);
                AlarmManager alarm = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    
                if (Build.VERSION.SDK_INT >= 26) {
                    PendingIntent pintent = PendingIntent.getForegroundService(getApplicationContext(), 6546548, serviceIntent, 0);
                    alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pintent);
                }else if (Build.VERSION.SDK_INT >= 23) {
                    PendingIntent pintent = PendingIntent.getService(getApplicationContext(), 6546548, serviceIntent, 0);
                    alarm.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), pintent);
                } else if (Build.VERSION.SDK_INT >= 19) {
                    PendingIntent pintent = PendingIntent.getService(getApplicationContext(), 6546548, serviceIntent, 0);
                    alarm.setExact(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis() , pintent);
                } else {
                    PendingIntent pintent = PendingIntent.getService(getApplicationContext(), 6546548, serviceIntent, 0);
                    alarm.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis() , pintent);
                }
    
            }
    
    
        private Calendar initCalendar(int hour, int minute, int second) {
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.HOUR_OF_DAY, hour);
            calendar.set(Calendar.MINUTE, minute);
            calendar.set(Calendar.SECOND, second);
    
            return calendar;
        }
    }