Как узнать текущее время и дату и установить конкретное время для действия в моем приложении - PullRequest
0 голосов
/ 09 июня 2018

Мое приложение набирает очки каждый день в 0000 часов в полночь, поэтому я хочу установить это время, а когда наступит время, установить время, в которое мое приложение будет добавлять очки автоматически, даже если приложение не открыто.

Я попробовал приведенный ниже код, но он не работает

//creates a time for 0000am
    String newDayTime = "00:00:00";
    Date date = java.sql.Time.valueOf(newDayTime);
    Calendar newDayDate = Calendar.getInstance();
    newDayDate.setTime(date);
    if(((today.getTime().after(newDayDate.getTime())))){
        dataa.edit().putFloat("blToday", blToday(select.this) + 15f).apply();
    }

Проблема с этим кодом заключается в том, что он не добавляет точку при достижении 12:00, и приложение также добавляет точку при каждом запуске,Каждый раз, когда я открываю приложение, оно добавляет очки. Как я могу исправить свой код?

Ответы [ 3 ]

0 голосов
/ 09 июня 2018

Если у вас очень чувствительная ко времени задача, вы должны использовать AlarmManager, которая будет выполняться в указанное время независимо от состояния системы.Если вы можете позволить себе гибкость, вы можете / должны использовать JobScheduler.Однако ключевой принцип JobScheduler заключается в том, что он решает, когда лучше всего выполнять вашу работу.Вы не можете гарантировать задержку в {x} минут.

Пример alaram manger

Calendar sixCalendar = Calendar.getInstance();
                    //set the time to 6AM
                    sixCalendar.set(Calendar.HOUR_OF_DAY, 6);
                    sixCalendar.set(Calendar.MINUTE, 0);
                    sixCalendar.set(Calendar.SECOND, 0);
    Intent intent = new Intent(this, AutoStartUp.class);   
     PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0,  intent, PendingIntent.FLAG_UPDATE_CURRENT);
     alarmMgr.setRepeating(AlarmManager.RTC_WAKEUP, sixCalendar.getTimeInMillis(),AlarmManager.INTERVAL_DAY, pendingIntent); 

Вот ваш класс получателя вещания

 public class AutoStartUp extends BroadcastReceiver{


    @Override
    public void onReceive(Context context, Intent intent) {
           specificMethod();// your method will be call here

    }
    }

Не делайтене забудьте зарегистрировать его mainfest

 <receiver android:name=".AutoStartUp"
                          android:enabled="true"
                        > 
                </receiver>
0 голосов
/ 09 июня 2018

Ответ Беры близок к правильному, но выбирает не совсем правильные java.time классы и методы.

ZonedDateTime & Instant, не LocalDateTime

Неверно используется класс LocalDateTime, в котором отсутствует понятие часового пояса или смещения от UTC.Таким образом, LocalDateTime не не представляет определенный момент на временной шкале.

Вместо этого используйте ZonedDateTime, чтобы представить конкретный момент со временем настенных часов, используемым людьмиконкретный регион (часовой пояс).

Часовой пояс имеет решающее значение при определении даты и времени суток.В любой момент времени дата меняется по всему земному шару в зависимости от зоны.Например, через несколько минут после полуночи в Париж Франция - это новый день, в то время как "вчера" в Монреаль Квебек .

Если часовой пояс не указан,JVM неявно применяет свой текущий часовой пояс по умолчанию.Это значение по умолчанию может измениться в любой момент во время выполнения (!), Поэтому ваши результаты могут отличаться.Лучше явно указать в качестве аргумента желаемый / ожидаемый часовой пояс .

Укажите правильное имя часового пояса в формате continent/region, например America/Montreal, Africa/Casablanca или Pacific/Auckland.Никогда не используйте 3-4-буквенное сокращение, такое как EST или IST, поскольку они не истинные часовые пояса, не стандартизированы и даже не уникальны (!).

ZoneId z = ZoneId.of( "America/Montreal" ) ;  
ZonedDateTime now = ZonedDateTime.now( z ) ;

Если вы хотите использовать текущий часовой пояс JVM по умолчанию, запросите его и передайте в качестве аргумента.Если опущено, текущее значение по умолчанию JVM применяется неявно.Лучше быть точным, так как значение по умолчанию может быть изменено в любой момент во время выполнения любым кодом в любом потоке любого приложения в JVM.

ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.

Извлечение части только для датыбез времени суток и без часового пояса.Любой java.time класс с именем «Local…» означает, что он «не зонирован», без какой-либо концепции зоны или смещения.

LocalDate ld = now.toLocalDate();  // Extract date-only without time-of-day and without offset-from-UTC.

Избегайте думать / говорить о «полуночи» как таковойстановится скользкой концепцией.Вместо этого сосредоточьтесь на «первом моменте дня».Итак, нам нужен первый момент завтрашнего дня.

Определите «завтра».

LocalDate tomorrow = ld.plusDays( 1 ) ;

Пусть java.time определит первый момент.Не думайте, что это будет время суток 00:00:00.Аномалии, такие как переход на летнее время (DST), означают, что день может начинаться в такое время, как 01:00:00.Укажите часовой пояс, разумеется, для обработки любых аномалий, влияющих на жителей этого региона, этого часового пояса.

ZonedDateTime tomorrowStart = tomorrow.atStartOfDay( z ) ;

Рассчитайте промежуток времени от настоящего момента до начала завтрашнего дня.Класс Duration представляет промежуток времени, не привязанный к временной шкале.

Duration d = Duration.between( now , tomorrowStart ) ;

Кстати, это может помочь вашему пониманию увидеть эти значения в UTC.Как программист (или системный администратор), вы должны думать в UTC.Забудьте о своем собственном приходском часовом поясе во время работы.

Класс Instant представляет момент на временной шкале в UTC с разрешением наносекунды (до девяти (9) цифр десятичной дроби).

Instant instantNow = now.toInstant() ;
Instant instantTomorrowStart = tomorrowStart.toInstant() ;
Duration d = Duration.between( instantNow , instantTomorrowStart ) ;

Эта пара Instant объектов представляет те же самые моменты, что и пара ZonedDateTime объектов.Те же точки на временной шкале, но разное время на настенных часах.Таким образом, результирующий расчет Duration такой же.

ScheduledExecutorService::schedule, а не scheduleAtFixedRate

Другой ответ правильный, предлагая ScheduledExecutorService запланировать задачу для запуска наопределенное время.

Но другие отвечают на звонкиscheduleAtFixedRate, который многократно выполняет одну и ту же задачу (a Runnable или Callable).Но Вопрос определяет требование, чтобы задача выполнялась в первый момент дня, каждый день.Это время дня может меняться в разные даты из-за аномалий, таких как Летнее время (DST) или других изменений в смещение от UTC , используемых конкретным часовой пояс. Эти изменения происходят на удивление часто, так как политики всего мира демонстрируют склонность к этим изменениям.Так что, если вы действительно хотите проверить первый момент дня, вам нужно пересчитывать продолжительность ожидания каждый раз, когда вы запускаете задачу.

Таким образом, вы должны попросить службу исполнения выполнить эту задачу только один раз.И в конце этой задачи запланируйте еще один запуск на следующий день.

Настройте службу исполнителя и сохраните ссылку на нее где-нибудь в своем приложении.Класс Executors предоставляет множество таких услуг.Получить счетчик SECONDS или NANOS из общего метода Duration::get.Использование наносекунд немного глупо, поскольку исполнитель не гарантированно работает с такой точностью.При этом всегда учитывается фактор выдумки, поскольку нагрузка на ядра вашего ЦП, многозадачное планирование вашей операционной системы, многопоточность вашей JVM могут повлиять, когда ваша задача действительно будет запущена.Поэтому я использую секунды здесь.

Кстати, немного сероборода совета ... Полночь - это час колдовства на компьютерах.Это когда многие операционные системы и приложения участвуют в операциях очистки и переноса, таких как создание новых файлов журнала.Некоторые программисты и системные администраторы предпочитают запускать некоторое время после полуночи или позже в середине ночи, например, в 2 или 3 часа ночи.

ScheduledExecutorService executorService = Executors.newSingleThreadExecutor() ;

Рассчитать задержку до первого выполнения.

long countUntilNextTaskRun = d.getSeconds() ; 

Запланируйте задачу, позвонив по номеру ScheduledExecutorService.schedule и указав время ожидания.

executorService.schedule( myRunnableOrCallable , countUntilNextTaskRun , unit ) ;

Возможно, вы захотите захватить ScheduledFuture для последующего использования.

ScheduledFuture<?> scheduledFuture = executorService.schedule( myRunnableOrCallable , countUntilNextTaskRun , TimeUnit.SECONDS ) ;

Эта задача будет выполняться только один раз.После того, как эта задача выполнит свою основную работу, она также запланирует следующий запуск, используя тот же код, что и выше.Рассчитайте время до следующего начала дня в этом конкретном часовом поясе.

Жизненный цикл

Служба исполнителя хранится в памяти вашего приложения.Это имеет два важных значения:

  • Обязательно выключите службу исполнителя.В противном случае пул потоков и запланированная задача могут остаться в памяти даже после закрытия приложения (в зависимости от реализации вашей JVM и хост-ОС).Таким образом, ваше приложение должно всегда определять, когда оно закрывается / завершается, и закрывать службу исполнителя.
  • Служба исполнителя не сохраняется после закрытия / выхода приложения.Поэтому, когда ваше приложение запускается, ваш код инициализации / запуска должен заново установить новую службу исполнителя.

Если ваши бизнес-требования требуют, чтобы вы наверстали упущенное в дни выполнения заданий, вам также потребуется запрограммировать задание на постоянную запись даты и времени (Instant) когда он в последний раз бежал.Затем вы вычисляете, сколько дней вы пропустили, используя те же классы и методы, которые обсуждались выше.


О java.time

java.time фреймворк встроен в Java 8 и более поздние версии.Эти классы вытесняют проблемные старые устаревшие классы даты и времени, такие как java.util.Date, Calendar, & SimpleDateFormat.

Проект Joda-Time , теперь в режиме обслуживания , рекомендует перейти на классы java.time .

Чтобы узнать больше, см. Oracle Tutorial .И поиск переполнения стека для многих примеров и объяснений.Спецификация JSR 310 .

Yoвы можете обмениваться java.time объектами напрямую с вашей базой данных.Используйте драйвер JDBC , совместимый с JDBC 4.2 или более поздней версии.Нет необходимости в строках, нет необходимости в java.sql.* классах.

Где получить классы java.time?

  • Java SE 8 , Java SE 9 , Java SE 10, а позже
    • Встроенный.
    • Часть стандартного Java API с встроенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и Java SE 7
    • Большая часть функций java.time перенесена на Java 6 & 7 в ThreeTen-Backport .
  • Android
    • Более поздние версии реализации связки Android классов java.time.
    • Для более ранних версий Android (<26) проект <a href="https://github.com/JakeWharton/ThreeTenABP" rel="nofollow noreferrer"> ThreeTenABP адаптируется ThreeTen-Backport (упомянуто выше).См. Как использовать ThreeTenABP… .
0 голосов
/ 09 июня 2018

Я думаю, вы должны использовать ScheduledExecutorService.Он выполнит отправленную задачу (Runnable / Callable) в назначенное время, а также задачу можно периодически повторять.

Создайте задачу, как показано ниже:

class UpdatePointWorker implements Runnable {
    @Override
    public void run() {
        // write your code here to update the ponints
        // dataa.edit().putFloat("blToday", blToday(select.this) + 15f).apply();
    }
}

Запланируйте задачу, как показано ниже:

    ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    Long midnight = LocalDateTime.now().until(LocalDate.now().plusDays(1).atStartOfDay(), ChronoUnit.MINUTES);
    Runnable task = new UpdatePointWorker();
    scheduler.scheduleAtFixedRate(task, midnight, 1440, TimeUnit.MINUTES);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...