Перейти к содержанию
Fire Monkey от А до Я

[Статья][Android] AlarmManager - Автозапуск приложения в назначенное время


Рекомендуемые сообщения

  • Модераторы

Ссылка: http://delphifmandroid.blogspot.ru/2016/02/alarmmanager-rad-studio.html

Автор: Ефимов Андрей

Описание: [AlarmManager] Автозапуск приложения в назначенное время

Ссылка на комментарий
  • 1 год спустя...

Привет.

Я тут узнал что оказывается начиная с XE7 не нужно создавать Dex файл затем подменять его на classes.dex.

Достаточно создать Jar файл и подключить его к проекту. 

Я проверил на новом проекте - все прекрасно работает. Проект автозапускается из AlarmManager (делал на основе этой статьи ) .А Dex файлы нужны для XE5 и XE6. Узнал я это из этого вопроса на stackoverflow.

Пожалуйста Вы не могли бы обновить статью? Просто дописав эту заметку? На мой взгляд это важно.

Я также обновил бат файл, 

он будет примерно такой:

@echo off
setlocal
 
if x%ANDROID% == x set ANDROID=c:\Users\Alex\Documents\Embarcadero\Studio\18.0\PlatformSDKs\android-sdk-windows
set ANDROID_PLATFORM=%ANDROID%\platforms\android-24
set PROJ_DIR=%CD%
set VERBOSE=0
 
echo.
echo Compiling the Java service activity source files
echo.
mkdir output 2> nul
mkdir output\classes 2> nul
if x%VERBOSE% == x1 SET VERBOSE_FLAG=-verbose
javac -source 1.7 -target 1.7 %VERBOSE_FLAG% -Xlint:deprecation -cp %ANDROID_PLATFORM%\android.jar -d output\classes src\com\TestReceiver\AlarmReceiver.java


echo.
echo Creating jar containing the new classes
echo.
mkdir output\jar 2> nul
if x%VERBOSE% == x1 SET VERBOSE_FLAG=v
jar c%VERBOSE_FLAG%f output\jar\test_classes.jar -C output\classes com


echo.
echo Now we have the end result, in directory output\jar\
pause

 

 

 

Также еще один ньюанс.  Для варианта 2 никакой Dex файл не нужен. Также не нужен и Jar файл. 
Также ничего не нужно в манифест добавлять, т.к. вызывается activity напрямую, без BroadcastReceiver.
Но это только для варианта 2. Для первого варианта (Broadcast) все это нужно.

Я проверял на новом проекте с вариантом 2 - все работает. 

Изменено пользователем ENRGY
Ссылка на комментарий
  • Модераторы

По поводу "как подключать JAVA класс":

процитирую ответ в блоге:

Цитата

По поводу JAR файла. Для подобных статей, я всегда стараюсь детально описать каждый шаг дальнейших действий. Это направлено на то, чтобы человек, начал понимать, что он делает, а не просто копипастить и потом на форуме кучу тем создавать с вопросами, как и что.
Если вам хочется добавлять JAR через Project Manager, то и пожалуйста, http://delphifmandroid.blogspot.ru/2015/03/jar.html

По поводу

Цитата

"Также еще один ньюанс.  Для варианта 2 никакой Dex файл не нужен. Также не нужен и Jar файл. 
Также ничего не нужно в манифест добавлять, т.к. вызывается activity напрямую, без BroadcastReceiver.
Но это только для варианта 2. Для первого варианта (Broadcast) все это нужно. "

Цитата из ответа в блоге:

Цитата

Да, всё правильно, для второго варианта dex не нужен. Два примера использованы в одном приложении. Видимо недостаточно понятно описал в статье, различия между getBroadcast и getActivity, а также между двумя тестовыми вариантами.

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

Но раз есть один прецедент, то может быть и второй. Поэтому я уже добавил прямое указание различий у двух примеров.

 

p.s. Не нужно заниматься кросспостингом.

 

Update. Все три статьи обновлены. Конкретно в этой статье постарался объяснить в тексте поверхностные отличия двух примеров, которые мне, до сегодняшнего дня казались очевидными.

Чуть позже выложу ещё всё на ГитХаб, чтобы не терялось :)

Ссылка на комментарий

Большое спасибо что поддерживаете статьи в актуальном состоянии!

Я также часто ссылаюсь на ваши статьи на других сайтах  - англоязычных.  Что удивительно подобная информация редко вcтречается на англоязычных сайтах, к примеру про Alarm Manager и Delphi нет ни одной статьи, даже на сайте Embarcadero этот вопрос долгое время висел без ответа, пока я не дал ссылку на вашу статью.

Непопулярность Delphi Mobile как раз и связана с тем, кроме цены, что на многие вопросы почти нет ответов, при этом Java сообщество пестрит готовыми Copy Paste решениями, что увеличивает и без того большую армию пользователей. Но Java нет на iOS. И на Java не сделаешь кроссплатформенный проект с единым кодом и GUI, поэтому Delphi здесь на шаг впереди.

Поэтому мне и показалось важным указать на ньюанс с JAR в темах связанными с DEX (заодно кстати и осветили баг с батником, помните javac -source 1.7 -target 1.7? - ведь на этом этапе у человека изучающего Delphi может пропасть желание изучать дальше),  столько плясок с бубном с этим dex, и разбросать чтобы больше людей увидели более удобный и простой вариант.

Изменено пользователем ENRGY
Ссылка на комментарий

Спасибо за статью, все отлично работает. Вот только не допру как запустить не приложение, а сервис. Все темы в разделе Сервис перечитал, но информацию не нашел :-(

Делаю по второму примеру:

procedure TForm2.Button2Click(Sender: TObject);
var
  Intent: JIntent;
  PendingIntent: JPendingIntent;
begin
  // Создаём Интент
  Intent := TJIntent.Create;
  Intent.setClassName(TAndroidHelper.Context, StringToJString('com.embarcadero.firemonkey.FMXNativeActivity'));
 
  // Оборачиваем Интент в PendingIntent
  PendingIntent := TJPendingIntent.JavaClass.getActivity(TAndroidHelper.Context, 1, Intent, 0);
 
  // Устанавливаем оповещение
  TAndroidHelper.AlarmManager.&set(TJAlarmManager.JavaClass.RTC_WAKEUP, getTimeAfterInSecs(30),
    PendingIntent);
end;

Но activity "com.embarcadero.firemonkey.FMXNativeActivity" одинаковые у приложения и сервиса. Запускается именно приложение. Как сделать только запуск сервиса?

Ссылка на комментарий
  • Модераторы

Евгений, внимательнее читайте статью, там есть раздел теории, а конкретно такие строчки:

Цитата
Основные методы:
  • getActivity –для запуска Activity
  • getBroadcast – для BroadcastReciver
  • getService – для Service

это половина ответа на ваш вопрос.

Вторую половину можно найти например в этой статье [Android Service+BroadcastReceiver] Автозапуск службы после рестарта ОС. В ней говорится, какое имя будет у сервиса после создания:

Цитата

Имя сервиса в студии всегда будет иметь начало «com.embarcadero.services.», а далее будет написано название вашего Сервиса.

 

Ссылка на комментарий

Andrey Efimov, огромное спасибо! Так и думал что глаз замылился и ответ перед глазами! Причем вашу статью раза четыре перечитал :-)

Ссылка на комментарий
  • 2 недели спустя...

Блин, проблема. Уже сутки не могу решить. 

Если телефон подключен к USB - то Alarm запускает активити. Если он на батареях, то он спит себе дальше и ничего не происходит. Ну понятно почему, - на батареях он уходит в sleep режим. 

Я уже пробовал и WakeLock и флаги FLAG_TURN_SCREEN_ON or FLAG_DISMISS_KEYGUARD or FLAG_SHOW_WHEN_LOCKED.- все в OnCreate (даже до и после Application.Initialize пробовал), пробовал и первый и второй метод со статьи (Activity и BroadcastReceiver) 

 

Проблема в том, что когда срабатывает RTC - система просыпается, но просыпается ненадолго. Где то на 2-3 секунды. Т,е. фактически не доходит до кода с WakeLock или кода с флагами (я уже пробовал его и до и после инициализации). 

Есть один рабочий вариант - ставить WakeLock в java коде с BroadcastReceiver (это кстати рекомендованный способ для запуска сервисов) - это работает, я пробовал, но я пока не знаю как отключить его. :) Пример

Возможно у кого то есть рабочий вариант? Был бы очень благодарен.

Странно что никто об этом не говорил..

Изменено пользователем ENRGY
Ссылка на комментарий

Ребят, а можете отозваться у кого работает без Wake Lock?

Возможно у автора статьи, ведь Андрей даже никаких намеков не давал.

Я просто удивлен что никто с этим не сталкивался.

Изменено пользователем ENRGY
Ссылка на комментарий

Фух. Наконец то проспался и понял как сделать.

Нужно просто поставить Alarm еще раз, напр. чтобы выполнился через 3 секунды.  (неудобный, есть вероятность попасть на ошибку)

просто вызвать его в Broadcast после Activity . (не всегда работает)

Запустить Activity и в BroadcastReceiver подождать 8 секунд, а затем там же снять WakeLock. 

Это вариант работает прекрасно.

Также с этим кодом Alarm срабатывает если Activity уже запущено либо в фоне. Нужно перехватывать WillBecomeForeground, BecameActive и там включать экран. Процессор включается в WakeLock, но не на долго, вам нужно включить экран при помощи функции ниже, сделать работу затем отключить экран).

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

 

Итак выстраданный бесcонными ночами Java код, обратите внимание на  TestLauncher.putExtra("StartedFromAM", true), это чтобы знать из Activity что запустились из Broadcast (предложенный Blong'гом EXTRA_ALARM_COUNT с BroadcastReceiver всегда вернет ноль, он работает только если запускать напрямую Activity!) : 

package com.TestReceiver;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.os.Handler;

public class AlarmReceiver extends BroadcastReceiver {
    
    private static PowerManager.WakeLock mWakeLock;

    @Override
    public void onReceive(Context context, Intent intent) {
	 

     if (mWakeLock == null) {
       PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
       mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Delphi");
       mWakeLock.acquire();
      }
           
           Intent TestLauncher = new Intent();                        
            TestLauncher.setClassName(context, "com.embarcadero.firemonkey.FMXNativeActivity");
            TestLauncher.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); // I
            TestLauncher.putExtra("StartedFromAM", true);
            context.startActivity(TestLauncher);  
   //
	
    Handler h = new Handler();
    h.postDelayed(new Runnable(){
             public void run(){
            
       mWakeLock.release();  
       mWakeLock = null;       
       
             }
           }, 8000);
 //Toast.makeText(context, "Reelase! ("+mcounter.toString()+")", Toast.LENGTH_SHORT).show(); // For example	
    }
}

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

Теперь в OnCreate нашей формы добавляем флаги чтобы включить экран, но при условии что  запустились мы из AlarmManager : 

function StartedFromAlarmManager: boolean;
begin
{$IFDEF ANDROID}
  Result := TAndroidHelper.Activity.getIntent.getBooleanExtra(StringToJString('StartedFromAM'), false);

  // this will work only if using Activity instead of Broadcast - TJPendingIntent.JavaClass.getActivity:
  //  Result := TAndroidHelper.Activity.getIntent.getIntExtra(TJIntent.JavaClass.EXTRA_ALARM_COUNT, 0);
{$ELSE}
  Result := false;
{$ENDIF}
end;

 

{$IFDEF ANDROID}
  procedure TurnOnAndKeepScreenAndroid(aEnable: boolean);
  var
    vFlags: integer;
  begin
    vFlags := TJWindowManager_LayoutParams.JavaClass.FLAG_TURN_SCREEN_ON or
        TJWindowManager_LayoutParams.JavaClass.FLAG_DISMISS_KEYGUARD or
        TJWindowManager_LayoutParams.JavaClass.FLAG_SHOW_WHEN_LOCKED or
        TJWindowManager_LayoutParams.JavaClass.FLAG_KEEP_SCREEN_ON;

    if aEnable then
    begin
      CallInUIThread (   // uses FMX.Helpers.Android
      procedure
      begin
        TAndroidHelper.Activity.getWindow.setFlags (vFlags, vFlags);
      end );
    end
    else
      CallInUIThread (
      procedure
      begin
        TAndroidHelper.Activity.getWindow.clearFlags (vFlags);
      end );
  end;
  {$ENDIF}

И сразу же отключаем наш WakeLock устанавливая второй раз Alarmmanager на срабатывание через 3 сек (соответственно запуститься BroadcastReceiver и освободит WakeLock).   (уже отключается сам в Broadcast сразу после старта Activity)- т.к. во флагах окна, уже указан FLAG_KEEP_SCREEN - это будет держать экран и систему включенной. 

Не забудьте  поставить разрешение WAKE LOCK = true!

 

 

 

 

Изменено пользователем ENRGY
Ссылка на комментарий

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...