Перейти к содержанию
  • 0
Pax Beach

Использование нативных LocalBroadcastManager и BroadcastReceiver

Вопросы

Из PlatformSDK (PlatformSDKs\android-sdk-windows\sources\android-23\android\support\v4\content\) портировал в Delphi класс TJLocalBroadcastManager.

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

Во вложении сам класс, в своем приложении убедитесь, что в Target Platforms (Android) → Android → Libraries включена библиотека android-support-v4.dex.jar.

 

Прилагаю пример, для изучения и использования в работе, который демонстрирует работу обычного BroadcastReceiver и LocalBroadcastReceiver.

В примере демонстрируется работа сообщений в приложении и сервисе. Сначала делаем build проекта LBCRService, потом будет доступна возможность собрать LocalBCR.

Собираю в Berlin 10.1, но на младших версиях тоже должно работать, по крайней мере в Seatlle.

 

В реализации методов

    procedure RegisterReceiver();
    procedure UnRegisterReceiver();

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

 

 

Androidapi.JNI.LocalBroadcastManager.pas.zip

LocalBroadCastReceiver.zip

Отредактировал Pax Beach
дополнил решение

Поделиться сообщением


Ссылка на сообщение

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

  • 0
56 минут назад, x11 сказал:

Подскажите, что нужно изменить в Ваших примерах, чтобы реагировать не на внутренние сообщения, а на внешние? Например, на звонки.

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

// Глобальные сообщения

и

// Локальные сообщения
 

соответственно то, что ниже этих комментариев, относится к локальному или глобальному ресиверу.

 

Поделиться сообщением


Ссылка на сообщение
  • 0

Подскажите, в чем может быть причина?

При запущенном приложении и службе работает Broadcast reciever (он внутри службы). И успешно получается перехватывать события, т.е. BroadcastReceiver.OnReceive срабатывает.

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

И даже вижу, что само приложение потом Андроидом запускается.

Тут же идея такова, что даже при закрытом приложении, должна срабатывать BroadcastReceiver.OnReceive.

Поделиться сообщением


Ссылка на сообщение
  • 0

Нашёл в логах андроида при смахивании приложения с экрана:

Цитата

ActivityManager: Scheduling restart of crashed service имя.пакета.программы/com.embarcadero.services.имя_службы in 3924ms

Т.е. служба почему-то закрывается аварийно.

 

Broadcast reciever создавался в событии StartCommand, продублировал ещё и в OnCreate DataModule.

Отредактировал x11

Поделиться сообщением


Ссылка на сообщение
  • 0
3 часа назад, x11 сказал:

Нашёл в логах андроида при смахивании приложения с экрана:

Т.е. служба почему-то закрывается аварийно.

 

Broadcast reciever создавался в событии StartCommand, продублировал ещё и в OnCreate DataModule.

Как обычно — причин может быть много.

Здесь читающих мысли и чужой код из астрала не встречал, нужно код смотреть.

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

Поделиться сообщением


Ссылка на сообщение
  • 0
7 часов назад, x11 сказал:

Т.е. служба почему-то закрывается аварийно.

емба сломала это еще в Берлине, в Токио не починили.

Службы "нормально" работают только в Сиетле

Поделиться сообщением


Ссылка на сообщение

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

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

Гость
Ответить на вопрос...

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

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

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

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

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


  • Похожий контент

    • От Евгений Корепов
      Я написал класс для демонизации приложения в linux. Класс форкает процесс, обрабатывает поступающие сигналы и передает их в основной поток через потокобезопасную очередь.
      Исходники https://github.com/EvgeniyKorepov/LinuxDaemon
      Для использования просто подключите модуль UnitDaemon в свое консольное приложение:
      program DaemonTest; {$APPTYPE CONSOLE} uses System.SysUtils, System.IOUtils, System.SyncObjs, Posix.Stdlib, Posix.SysStat, Posix.SysTypes, Posix.Unistd, Posix.Signal, Posix.Fcntl, Posix.Syslog in 'Posix.Syslog.pas', UnitDaemon in 'UnitDaemon.pas'; var AEventType : TEventType; begin syslog(LOG_NOTICE, 'main START'); while True do begin syslog(LOG_NOTICE, 'main LOOP'); if UnitDaemon.QueueEvent.PopItem(AEventType) = System.SyncObjs.TWaitResult.wrSignaled then begin syslog(LOG_NOTICE, 'main UnitDaemon.QueueEvent.PopItem'); case AEventType of TEventType.StopProcess : begin syslog(LOG_NOTICE, 'main Event StopProcess'); ExitCode := EXIT_SUCCESS; exit; end; TEventType.Start : begin syslog(LOG_NOTICE, 'main Event START'); end; TEventType.Reload : begin // Reload config syslog(LOG_NOTICE, 'main Event RELOAD'); end; TEventType.Stop : begin syslog(LOG_NOTICE, 'main Event STOP'); ExitCode := EXIT_SUCCESS; exit; end; end; end; Sleep(50); end; end. Так же поддерживается systemd - для этого положите  DaemonTest.service в /etc/systemd/system/ и используйте :
      systemctl start DaemonTest.service systemctl reload DaemonTest.service systemctl stop DaemonTest.service  
    • От Евгений Корепов
      Вот просто идеальная статья по запуску демона под Linux http://blog.paolorossi.net/2017/09/04/building-a-real-linux-daemon-with-delphi-part-2/ 
      Помимо объяснения механизма fork с отличными примерами,  есть куча дополнительной наиполезнейшей инфы.
    • От x11
      Это не вопрос. Просто подумал, что кому-нибудь может пригодится.
      https://forums.embarcadero.com/thread.jspa?threadID=118465
      Используем 2 файла: Androidapi.JNI.ToastForService.pas + FlyUtils.Android.PostRunnableAndTimer.pas.
      Пример вызова:
      Androidapi.JNI.ToastForService.PostToast('текст сообщения', LongToast); Проверил - работает.
      Есть ещё третий параметр "UseLastToastObj", но я так и не понял, для чего он. Документации нет.
    • От x11
      Приложение + служба.
      В службе установлен флаг перезапуска в StrartCommand^
      result := TJService.JavaClass.START_STICKY; // rerun service if host app stops  
      Проблема вот в чем. На экране главная форма хост-приложения.  На смартфоне внизу нажимаю кнопку Назад. Приложение закрывается.
      Вижу в LogCat Андроида, что аварийно завершается служба. Андроид восстанавливает работу службы и запускает и службу и само приложение. Хотя Андроид не должен перезапускать host-приложение, а только службу.
       
       
      Т.е. вижу, что поле выхода приложение со службой работают.
      Когда с рабочего стала ланчера запсукаю host-приложение, то оно виснет при старте и даже событие OnCreate главной формы не срабатывает. Показывается стартовое окно (splash) и висит, пока Андроид не предложит закрыть или подождать. И так несколько раз приходится делать, пока приложение не запустится.
      Я в OnClose главной формы разные параметры прописывал для action, но толку нет.
      Хоть какой-нибудь костыль посоветуйте, пожалуйста.
       
      А когда нажимаю кнопку Домой на смартфоне, то приложение сворачивается и тогда запсу с рабочего стола ланчера происходит нормально, т.е. приложение просто всплывает.
      Может можно как-то при закрытии приложения не закрывать его, а сворачивать?
      Если я не запускаю службу, то приложение закрывается и потом запускается нормально с рабочего стола ланчера.
      Заранее благодарен.
    • От brunnengi
      Здравствуйте.
      Требуется программа на андроид с набором кнопок со следующем функционалом:
      1. Кнопка1 - создать базу в test.sqlite (в том месте где доступ к нему есть только у самого приложения (имею ввиду если это не ROOT телефон, при рут и так всё понятно)
      2. Кнопка2 - создать таблицу в базе test.sqlite с названием "TblTest01" (с разным набором полей на своё усмотрение)
      3. Кнопка3 - создать таблицу в базе test.sqlite с названием "TblTest02" (с разным набором полей на своё усмотрение)
      4. Кнопка4 - Добавить строку в таблицу "TblTest01" (любой набор данных на ваших усмотрение)
      5. Кнопка5 - Удалить строку в таблице "TblTest01" (по любому ключу на ваше усмотрение)
      6. Кнопка6 - Изменить строку в таблице "TblTest01" (по любому ключу и любое значение на ваше усмотрение)
       
      Приложение должно иметь фоновый сервис, который должен получать данные с сервера и добавлять их в базу test.sqlite в таблицу "TblTest02".
      При получение новый данных, сервис должен показать в "шторке" сообщение, по клику на которую открывается само приложение с визуальной частью.
      Т.е. если визуально приложение закрыто, выгружено, не запущено или запущено, фоновый процесс должен сам делать запросы к серверу и добавлять новые данные в базу, если они есть/поступили
      Приложение должно запускаться вместе с системой, после перезагрузки и т.д.
      Использовать только те компоненты что доступны в самой среде из коробки.
      Часть где делается запрос к серверу должен иметь timeout равный 20 секундам.
      Сервис должен грамотно делать запросы к серверу как положено в Андроид приложениях. 
      Серверная часть мне не нужна, можете для теста сами эмулирвать эти процессы.
       
       
      -----
      ЦЕНА: 2500р.
      СРОКИ: Не горит, но в целом где то дней 7 есть
      Перечисляю на QIWI, ЯД, Сбербанк, короче куда скажите.
    • От x11
      Как проверить, работает ли моя служба?
      Т.е. перед запуском или остановкой хочется выполнить проверку.
       
      FService := TJIntent.Create; FService.setClassName(TAndroidHelper.Context.getPackageName, TAndroidHelper.StringToJString('com.embarcadero.services.pak1')); FService.setAction(StringToJString('StopService')); TAndroidHelper.Activity.startService(FService);  
    • От x11
      Так и должно быть, что событие "BroadcastReceiver.OnReceive" срабатывает 2 раза подряд?
      Код создания. Проверял: создается только один BroadcastReceiver.
      procedure TDMSrv.CreateBroadcastReceiver; begin BroadcastReceiver := TCSBroadcastReceiver.Create(nil); BroadcastReceiver.OnReceive := BroadcastReceiverOnReceive; BroadcastReceiver.RegisterReceive; BroadcastReceiver.Items.Clear; BroadcastReceiver.Add(PHONE_STATE); BroadcastReceiver.Add(NEW_OUTGOING_CALL); Log('CreateBroadcastReceiver'); end;  
      Сам код события:
      procedure TDMSrv.BroadcastReceiverOnReceive(csContext: JContext; csIntent: JIntent); begin log('BroadcastReceiverOnReceive'); CheckPhoneCallState(csContext, csIntent); end;  
      Ну и сама процедура обработки:
      procedure TDMSrv.CheckPhoneCallState(Context: JContext; Intent: JIntent); var telephonyService: JObject; telephonyManager: JTelephonyManager; state: JString; incomingCallNumber: string; outgoingCallNumber: string; outputResult: string; begin Log('CheckPhoneCallState: ' + JStringToString(Intent.getAction)); outputResult:= sLineBreak; telephonyService := TAndroidHelper.Context.getSystemService(TJContext.JavaClass.TELEPHONY_SERVICE); telephonyManager := TJTelephonyManager.Wrap((telephonyService as ILocalObject).GetObjectID); if JStringToString(Intent.getAction).Equals(PHONE_STATE) then begin state := Intent.getStringExtra(TJTelephonyManager.JavaClass.EXTRA_STATE); if state.equals(TJTelephonyManager.JavaClass.EXTRA_STATE_IDLE) then outputResult:= outputResult + 'Phone is IDLE ' + sLineBreak else if state.equals(TJTelephonyManager.JavaClass.EXTRA_STATE_RINGING) then begin incomingCallNumber := JStringToString(Intent.getStringExtra(TJTelephonyManager.JavaClass.EXTRA_INCOMING_NUMBER)); if incomingCallNumber.Equals('') then incomingCallNumber:= 'PRIVATE NUMBER'; outputResult := outputResult + 'Phone is RINGING' + sLineBreak; outputResult := outputResult + 'Incoming call from ' + incomingCallNumber + sLineBreak; LaunchNotification(incomingCallNumber, 'Входящий вызов'); InsertTel(incomingCallNumber, True); end else if state.equals(TJTelephonyManager.JavaClass.EXTRA_STATE_OFFHOOK) then outputResult:= outputResult + 'Phone is OFFHOOK' + sLineBreak; end else if JStringToString(Intent.getAction).Equals(NEW_OUTGOING_CALL) then begin outgoingCallNumber:= JStringToString(Intent.getStringExtra(TJIntent.JavaClass.EXTRA_PHONE_NUMBER)); outputResult:= outputResult + 'Outgoing call to ' + outgoingCallNumber + sLineBreak; LaunchNotification(outgoingCallNumber, 'Исходящий вызов'); InsertTel(outgoingCallNumber, False); end; Log(outputResult); end;  

    • От x11
      На основе нескольких тем форума сделал службу перехвата звонков и номера телефона.
      http://fire-monkey.ru/topic/3878-статьякак-создать-простой-android-broadcast-receiver-how-to-implement-simplest-android-broadcast-receiver-in-delphi/
      http://fire-monkey.ru/topic/2386-перехват-события-звонка/
      http://fire-monkey.ru/topic/2972-использование-нативных-localbroadcastmanager-и-broadcastreceiver/
      Покритикуйте пожалуйста. Уверен, что не всё правильно.
      Но что до ума не удалось довести, так это то, как правильно останавливать службу и закрывать приложение.
      Проект (для Токио) приложил теме.
      Заранее благодарен.
       
      BR2.rar
    • От x11
      Заметил, что после удаления библиотеки-сервиса всё равно в host-приложении остаётся мусор.

    • От x11
      Прошу помощи или хотя бы совета.
      Кто-то уже пытался создать службу, которая может перехватывать звонки входящие и исходящие?
      Пример для обычного приложения есть с таким кодом
      TPlatformServices.Current.SupportsPlatformService(IFMXPhoneDialerService, IInterface(PhoneDialerService)); if Assigned(PhoneDialerService) then PhoneDialerService.OnCallStateChanged := MyOnCallStateChanged;  
      Плюс пытаюсь всё это скрестить с NotificationCenter, но служба при запуске зависает и падает.
       
       
  • Последние посетители   0 пользователей онлайн

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

×
×
  • Создать...