Android: будильник срабатывает раньше запланированного времени

Я пытаюсь сгенерировать сигнал тревоги через 10 минут после запуска приложения. Согласно моему требованию, этот будильник должен срабатывать независимо от того, закроет ли пользователь приложение, выключит и снова включит или даже после перезагрузки. Ниже мой код.

MainActivity.java

import android.app.ActivityManager;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

import java.util.List;

public class MainActivity extends AppCompatActivity {

    private Context context;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        this.context=this;

        startService(new Intent(getBaseContext(), MyService.class));

    }

    public void startService(View view) {
      //  startService(new Intent(getBaseContext(), MyService.class));
    }

    // Method to stop the service
    public void stopService(View view) {
      //  stopService(new Intent(getBaseContext(), MyService.class));
    }

}

MyService.java — это класс службы.

import android.app.AlarmManager;
import android.app.IntentService;
import android.app.PendingIntent;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.IBinder;
import android.os.SystemClock;
import android.widget.Toast;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Calendar;
import java.util.GregorianCalendar;

/**
 * Created by Nirodha Mihiran on 6/8/2016.
 */
public class MyService extends Service {

    public static boolean doneCreted = false;

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


    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // Let it continue running until it is stopped.

        Toast.makeText(this, "Service Started Second", Toast.LENGTH_LONG).show();

        Calendar calendar = new GregorianCalendar();
        calendar.setTimeInMillis(System.currentTimeMillis() + 10 * 60 * 1000);

        intent = new Intent(MyService.this, AlarmReceiver.class);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(MyService.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        AlarmManager am = (AlarmManager) MyService.this.getSystemService(MyService.this.ALARM_SERVICE);
        // am.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 1000 * 60 * 5, pendingIntent);
        // am.setWindow(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(), 1000 * 60 * 5 , pendingIntent);
        am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);

        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
    }

}

AlarmReciever.java

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import android.widget.Toast;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.GregorianCalendar;

/**
 * Created by thisararanawaka on 6/2/16.
 */
public class AlarmReceiver extends BroadcastReceiver {
    private int MID = 0;

    public static boolean isCreated;

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO Auto-generated method stub

        long when = System.currentTimeMillis();

        Calendar calendar = new GregorianCalendar();
        calendar.setTimeInMillis(System.currentTimeMillis()+5*60*1000);

        NotificationManager notificationManager = (NotificationManager) context
                .getSystemService(Context.NOTIFICATION_SERVICE);

        Intent notificationIntent = new Intent(context, MainActivity.class);
        notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
                notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

        Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

        NotificationCompat.Builder mNotifyBuilder = new NotificationCompat.Builder(
                context).setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("Alaram Fired")
                .setContentText("Events To be Performed").setSound(alarmSound)
                .setAutoCancel(true)
                .setContentIntent(pendingIntent)

                .setVibrate(new long[]{1000, 1000, 1000, 1000, 1000});
        notificationManager.notify(MID, mNotifyBuilder.build());
        MID++;

        Toast.makeText(context, "Notification Created .", Toast.LENGTH_LONG).show();
    }
}

У меня нет проблем со срабатыванием будильника, если я не выключил и не выключил телефон или не перезагрузил телефон. Я вовремя ставлю будильник.

Однако, если я выключаю и включаю телефон или перезагружаю телефон, я получаю сигнал тревоги и уведомление сразу после включения / перезагрузки телефона - может быть, через одну минуту. В этом случае, даже если будильник запланирован на завтра, это не имеет значения, я срабатываю, как только телефон включается/перезагружается.

Что я сделал не так?


person Terance    schedule 30.06.2016    source источник
comment
Alarm Manager сбрасывается при перезагрузке телефона. См. решение для этого на stackoverflow.com/a/38093353/2435238.   -  person sJy    schedule 30.06.2016
comment
@sJy: У этого решения есть проблемы, оно не работает, когда телефон выключен и включен. Аварийный сигнал после перезапуска также не гарантируется.   -  person Terance    schedule 30.06.2016
comment
Это решение показывает, как перехватить событие завершения загрузки из нашего приложения. Затем для установки будильника нам нужно добавить код в onReceive()   -  person sJy    schedule 30.06.2016
comment
@sJy: Глядя на мой код, вы предполагаете, что создание тревоги должно перейти в метод onRecieve класса AlarmReciever?   -  person Terance    schedule 30.06.2016
comment
Существующее создание тревоги должно оставаться в самом классе обслуживания. Но для класса BootCompleteReceiver onReceive() вы должны снова установить будильник, чтобы при повторном включении телефона был создан будильник.   -  person sJy    schedule 30.06.2016
comment
@sJy: Спасибо. К сожалению, теперь будильник срабатывает через 5 минут после перезагрузки телефона. Например, если я открою приложение сейчас, я ожидаю, что будильник сработает через 5 минут, через 2 минуты я перезапущу телефон (что означает, что будильник должен сработать через 3 минуты), но будильник сработает через 5 минут после перезапуска.   -  person Terance    schedule 30.06.2016
comment
Аварийные сигналы не сохраняются при перезагрузке. Вы обрабатываете событие BOOT_COMPLETED? Пожалуйста, опубликуйте манифест и код для вашего BOOT_COMPLETED приемника.   -  person David Wasser    schedule 05.07.2016


Ответы (1)


Изучив ваш код, это может быть причиной

В вашем onStartCommand() вы устанавливаете время как calendar.setTimeInMillis(System.currentTimeMillis() + 10 * 60 * 1000);

который устанавливает календарное время + 10 минут, а затем вы устанавливаете то же время в строке ниже am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);

Попробуйте так,

long myAlarmTime = System.currentTimeMillis() + 10 * 60 * 1000; am.set(AlarmManager.RTC_WAKEUP, myAlarmTime, pendingIntent);

Причина, по которой возникает эта проблема при перезапуске

Есть две причины, по которым служба может запускаться системой. Если кто-то вызывает Context.startService(), то система извлекает службу (создает ее и вызывает метод onCreate(), если это необходимо), а затем вызывает метод onStartCommand(Intent, int, int) с аргументами, предоставленными клиентом. В этот момент служба будет продолжать работать до тех пор, пока не будет вызван метод Context.stopService() или stopSelf(). https://developer.android.com/reference/android/app/Service.html

person Clement Amarnath    schedule 30.06.2016