Search code examples
javaandroidalarmmanager

Calling Service From Broadcastreceiver not working as expected


I want my service to run at a time specified from alarm manager. But in my case its running on the time i have specified and also if i open the app after the time specified service runs. I want it to run only on the time specified and it should repeat everyday. I don't know what is wrong in the code i have written. Any help is appreciated.

This is my service class:

public class AutoLogout extends Service {

private SQLiteHandler db;
private SessionManager session;

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

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    // SqLite database handler
    db = new SQLiteHandler(getApplicationContext());
    // session manager
    session = new SessionManager(getApplicationContext());
    logoutUser();
   Toast.makeText(getApplicationContext(),"Service started",Toast.LENGTH_SHORT).show();
    return Service.START_STICKY;
}

/**
 * Logging out the user. Will set isLoggedIn flag to false in shared
 * preferences Clears the user data from sqlite users table
 */
private void logoutUser() {
    session.setLogin(false);
    db.deleteData();
    // Launching the login activity
    Intent intent = new Intent(this, LoginActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
    startActivity(intent);
    stopService(new Intent(getApplicationContext(),AutoLogout.class));
    Toast.makeText(getApplicationContext(),"Service stopped",Toast.LENGTH_SHORT).show();
}
}

This is my BroadcastReciever class:

public class AlarmBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "MyReceiver Started", Toast.LENGTH_SHORT).show();
        Intent intent1 = new Intent(context,AutoLogout.class);
        context.startService(intent1);
    }
}

CategoryActivity.java where i am calling alarm manager in oncreate method:

public class CategoryActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_category);
    Calendar cal_alarm = Calendar.getInstance();
            cal_alarm.set(Calendar.HOUR_OF_DAY,14);
            cal_alarm.set(Calendar.MINUTE,46);
            cal_alarm.set(Calendar.SECOND,00);
            Intent intent = new Intent(this, AlarmBroadcastReceiver.class);
            PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), 234324243, intent, PendingIntent.FLAG_ONE_SHOT);
            AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
            alarmManager.setExact(AlarmManager.RTC_WAKEUP, cal_alarm.getTimeInMillis() , pendingIntent);

}
}

This is in my manifest file:

    <service android:name=".services.AutoLogout" />
    <receiver android:name=".services.AlarmBroadcastReceiver"/>

Solution

  • The problem is happening because each time you open the activity which sets the alarm, it is re-initializing the alarm - however, the alarm is incorrectly firing right away each time you open the activity because the correct alarm time (14:46:00) has likely already passed on the current day, and when you set an AlarmManager alarm for a time that has already passed, it fires immediately.

    In order to fix this, we need to check if the alarm time has already passed for the current day, and if it has, set the alarm for 14:46:00 on the following day:

    if (cal_alarm.getTimeInMillis() < System.currentTimeMillis()) {
            cal_alarm.add(Calendar.DATE, 1);
    }
    

    Here is how it would look inside of your CategoryActivity:

    public class CategoryActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_category);
            Calendar cal_alarm = Calendar.getInstance();
            cal_alarm.setTimeInMillis(System.currentTimeMillis()); // i added this to ensure the calendar is being configured correctly
            cal_alarm.set(Calendar.HOUR_OF_DAY,14);
            cal_alarm.set(Calendar.MINUTE,46);
            cal_alarm.set(Calendar.SECOND,00);
    
            //check if time has already passed today, adjust alarm to tomorrow if it has
            if (cal_alarm.getTimeInMillis() < System.currentTimeMillis()) {
                cal_alarm.add(Calendar.DATE, 1);
            }
    
            Intent intent = new Intent(this, AlarmBroadcastReceiver.class);
            PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), 234324243, intent, PendingIntent.FLAG_ONE_SHOT);
            AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
            alarmManager.setExact(AlarmManager.RTC_WAKEUP, cal_alarm.getTimeInMillis() , pendingIntent);
        }
    }
    

    The if statement simply checks if the current time is larger than the time that cal_alarm is set for, and if it is, sets the alarm for 14:46:00 tomorrow. If you need any more clarification feel free to ask!