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

ENERGY

Пользователи
  • Постов

    568
  • Зарегистрирован

  • Посещение

  • Победитель дней

    57

Сообщения, опубликованные ENERGY

  1. Есть какие то результаты? Тоже интересует эта тема.

    На iOS нельзя отправить SMS в фоне без разрешения пользователя. Это искуcственный запрет от Apple.  Максимум что можно сделать это только отправить текст смс в специальный компонент системы, это сообщение потом будет показано пользователю, который решит  можно ли отправлять сообщение или нет. 

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

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

  2. Как увеличить количество последних сообщений? Это панель на форуме справа.

    Фактически это текущий, основной форум, это жизнь форума. 

    20 тем это мало, бывает пару дней не появишься, и пропустишь интересные темы уже навсегда. 

    Хотя бы 30 надо..

    Это еще людей на форуме мало, будет в раза 2-3 больше, - состав последних сообщений будет очень быстро меняться, в результате вероятность что вопрос останется без ответа увеличиться...

     

    Еще вопрос как найти свои темы?

     

    Зашел в настройки, там не нашел ни того ни другого..

    Спасибо.

  3. Тоже столкнулся с этим багом. Delphi Berlin update 2. А баг есть в QC?

    Я так понял проблема в MultiView, проще сделать popup меню вообще без MultiView - здесь описание:

    http://docwiki.embarcadero.com/RADStudio/Seattle/en/Mobile_Tutorial:_Using_ListBox_Components_to_Display_a_Table_View_(iOS_and_Android)

    Вообще по идее MultiView должен сам снимать выделение перед показом листбокса, странно что так не сделали. 

  4. TMonchromeEffect подойдет для контролов. Для моего случая подходит.

    Но он не работает. Пишет "Class TMonochromeEffect not found" - добавляю как обычный эффект. В DesignTime работает.  При запуске выбрасывает такое исключение.

    Кидаю вместо него TGlowEffect  - работает без проблем. 

     

    А как сделать это для картинки в runtime, есть ли какая-то процедура, вообще?

  5. Как сделать картинку TBitmap  серой, т.н. неактивной? Возможно в FMX уже есть какие то эффекты или готовые методы для этого?

    Нужно для сгруппированных TSpeedButton  - стили segmentedbuttonleft, segmentedbuttonmiddle итп.

     

     

     

  6. Еще мультипоточный вариант отсюда

     

    class procedure TFireMonkey.CachePictures(const aLV: TListView);
    begin
      Pool.SetMaxWorkerThreads(10); // TThreadPool.Default.MaxWorkerThreads
    
      TParallel.For(0, FMembersList.Count - 1,
        procedure(Idx: Integer)
        var
          AHTTP: TIdHTTP;
        begin
          if not FileExists(FMembersList[Idx].FileName) then
          begin
            AHTTP := TIdHTTP.Create(nil);
            try
              AHTTP.HandleRedirects := true;
              FStreamList[Idx].Clear;
              AHTTP.Get(FMembersList[Idx].URL, FStreamList[Idx]);
            finally
              FreeAndNil(AHTTP);
            end;
    
            TThread.Queue(TThread.CurrentThread,
              procedure
              var
                AItem: Integer;
              begin
                if FStreamList[Idx].Size > 0 then
                begin
                  FStreamList[Idx].SaveToFile(FMembersList[Idx].FileName);
                  AItem := Trunc(Idx / aLV.Columns);
                  if AItem < aLV.Items.Count then
                    aLV.Adapter.ResetView(aLV.Items[AItem]);
                end;
                Log.d('Current Thread = ' + inttostr(Idx));
              end);
          end;
        end, Pool);
    end; 

     

    После загрузки ставьте boolean флаг в своем массиве, обозначающий что картинка загружена. Btw Boolean у Intel и ARM можно записывать и читать без синхронизации между потоками (Т.е. не нужно использовать TMonitor или AtomicExchange ), если он не в packed структуре (packed record).

  7. krapotkin

    На мой взгляд формат ini наиболее удобный - Секция > Имя=значение.

    1. Не нашел как делить настройки на секции - в этом основное преимущество ini. 

    2. Парсинг json требует больше времени чем ini. Если настроек много, то это будет в несколько раз медленнее варианта ini. Например в моем проекте кроме основных настроек, есть еще группы, профайлы, и кампании.

    И очень удобно когда секции ссылаются друг на друга, причем втч. читать сам ini файл в текстовом редакторе. 

    К примеру : 

    [Group1]

    Key=Value

    [Profile2]

    Key=Value

    [Campaign1]

    Groups=Group1, Group2

    Profiles=Profile1, Profile2 

    [Campaign2]

    [Campaign3]

     

  8. В Unix нет реестра, там все на файлах.  Android, MacOS и iOS - это Unix. 

    В Android есть 2 варианта для сохранения данных, которые не будут удалены после деинсталяции - сохранять на SD карту, и сохранять удаленно в свою базу (через интернет). 

    http://stackoverflow.com/questions/19683614/android-persist-data-after-uninstall

    Хотя можно попробовать записать что-то и во внутреннее хранилище, в папки Music, Ringtones итп  почитайте здесь статью Saving files that can be shared with other apps

     

     

  9. Это касается ARC компиляторов, Android, iOS и будущего Linux.

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


    А дело было так - при вызове MyCore.Free класс не уничтожался - не вызывался деструктор из за того, что после вызова Free, счетчик ссылок (reference Count) был равен 1. Приходилось пользоваться  DisposeOf. Решил разобраться.

    Для этого перекрыл виртуальные методы TObject отвечающие за изменения счетчика объекта (см. также полный пример ниже).

    function __ObjAddRef: Integer; override;
    function __ObjRelease: Integer; override;

     

    Итак TCore содержит класс TTestClass - у которого есть событие OnMyEvent. 
    Прототип описан как анонимная процедура - TAnonymProc = reference to procedure;


    При указании анонимной процедуры, т.е. : 

    procedure TCore.SetEvent;
    begin
      fTest.OnMyEvent := procedure ()
      begin
        fSetFlag := true;
      end;
    end;

    счетчик ссылок TCore увеличивается на 1 и не изменяется при выходе из SetEvent.

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


    Решение : 
    1. Использовать слабые ссылки - weak, в нашем примере добавить атрибут [weak]:

    TTestClass = class
    strict private
      [weak]fOnMyEvent:TAnonymProc;
    public
      property OnMyEvent: TAnonymProc read fOnMyEvent write fOnMyEvent;
    end; 

    При присваивании объекта в переменную со слабой ссылкой не происходит увеличение счётчика ссылок объекта на единицу. Аналогично, при очистке слабой ссылки не происходит уменьшение счётчика объекта на единицу.

    2. Не использовать анонимные методы, а использовать обычные указатели на метод: 
    Вместо TAnonymProc = reference to procedure; используем классический 
           TAnonymProc = procedure of object;


    Демо пример, где можно отследить утечку прикрепил.

    Полный код: 

    Спойлер

     

    
    unit Unit1;
    
    interface
    
    uses
      System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
      FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls;
    
    type
      TAnonymProc = reference to procedure;
      TTestClass = class
      strict private
        fOnMyEvent:TAnonymProc;
      public
        property OnMyEvent: TAnonymProc read fOnMyEvent write fOnMyEvent;
      end;
    
      TCore = class (TObject)
      strict private
        fTest: TTestClass;
        fSetFlag: boolean;
      public
        constructor Create;
        destructor Destroy; override;
        procedure SetEvent;
        function __ObjAddRef: Integer; override;
        function __ObjRelease: Integer; override;
      end;
    
    
      TForm1 = class(TForm)
        Button1: TButton;
        Button2: TButton;
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
      private
        fCore: TCore;
      public
        { Public declarations }
      end;
    
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.fmx}
    
    procedure TForm1.Button2Click(Sender: TObject);
    begin
      fCore := TCore.Create;
      fCore.SetEvent;
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      Tag := fCore.RefCount;
      fCore.Free;
    end;
    
    { TCore }
    
    constructor TCore.Create;
    begin
      fTest := TTestClass.Create;
    end;
    
    destructor TCore.Destroy;
    begin
      fTest.Free;
      inherited;
    end;
    
    procedure TCore.SetEvent;
    begin
      fTest.OnMyEvent := procedure ()
      begin
        fSetFlag := true;
      end;
    
    end;
    
    // test it on ARC compilers like Android, iOS
    function TCore.__ObjAddRef: Integer;
    begin
      Result := inherited __ObjAddRef;
    end;
    
    function TCore.__ObjRelease: Integer;
    begin
      Result := inherited __ObjRelease;
    end;
    
    end.

     

     

     

    AnonMethodsCycle.zip

  10. Правильней будет сначала обнулить Родителя, затем вызвать Free.  Чтобы уменьшить счетчик ARC. При присваивании класса этот счетчик увеличивается (т.к. появилась еще одна ссылка на него), и при обнулении ссылки - уменьшается. Можно поставить точку останова на деструктор  вашего класса, чтобы точно узнать вызывается он или нет.

    При вызове Free на ARC компиляторах (а это iOS, Android и будущий Linux) - компилятор вызовов Free  переделает в обычное обнуление.

    procedure TObject.Free;
    begin
    // under ARC, this method isn't actually called since the compiler translates
    // the call to be a mere nil assignment to the instance variable, which then calls _InstClear
    {$IFNDEF AUTOREFCOUNT}
      if Self <> nil then
        Destroy;
    {$ENDIF}
    end;

    Кстати в вашем случае, как написали выше лучше использовать дженерик TObjectList из System.Generics.Collections. Кстати он уничтожает объекты при помощи DisposeOf.

     

    Насчет DisposeOf.  Эта конструкция явно вызывается деструктор объекта, но не освобождает память которая выделена под объект. Т.е. при обращении к такому "уничтоженному" объекту, не произойдет нарушения доступа (Access Violation). Такой объект называется зомби объект.

    Вот интересная статья, очень советую  http://www.gunsmoker.ru/2013/05/modern-delphi.html

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

    У себя в проекте я в основном использую free (или FreeAndNil - в случае когда нужно проверять был ли уже создан ли объект (MyTObj <> nil).

  11. 7 часов назад, krapotkin сказал:

    вадим, из вашего текста следует, что у вас все формы создаются при старте приложения

    но это и раньше было плохой практикой, а на мобилах и подавно

    Да кстати это плохая практика. К примеру под iOS если программа потребляет много памяти сначала получает didReceiveMemoryWarning, затем автоматом убивается системой.

    Android попроще в этом плане, но тоже особо не жалует, и если такая прога будет в фоне, и как только потребуется память, то первыми на вылет.

    В общем это не Винда с ее "бесконечным" виртуальным свопом..

    И хотя игрушки тянут гораздо больше памяти, а FMX гораздо меньше, но все такие вы должны быть в курсе.

  12. Цитата

    Слать пуш, с призывом открыть приложение и что то совершить! :))

     

    Офигеть. А для пуша нужно подключение к интернет верно? А для пуша нужен свой сайт на хостинге? Или можно как -то использовать сервера Apple?

  13. 1 час назад, wamaco сказал:

    Вам хорошо с AlarmManager, а что делать любителям iOS?

     

    Можно об этом поподробнее? На днях как раз собираюсь iOS версию делать, и там нужен будет Alarm Manager. Т.е. там его нет? Как тогда можно запускать запланированные задания? Сервис в фоне?

  14. Поменяйте цвет этих иконок. В любой редакторе можно сдвинуть HUE (я обычно использую Axialis Icon Workshop и Photoimpact) - смещение цветов. 

    И вам будет удобно, и не должны отказать.

    Можно также поискать Online Image\photo editor - но они как правило очень бедные по функционалу, и там может не быть изменения HUE.

  15. Мой вариант Broadcast Receiver, на мой взгляд наиболее оптимизирован и удачен. По сравнению с известным кодом от barisatalay .

    Отличия -

    исправлена утечка,

    чуть быстрее работает, за счет того что создается один фильтр в него добавляется несколько Actions  и одна регистрация на него, 

    нет лишних конвертирований с Jstring to string и обратно,

    адаптирован под Delphi 10 (JFMXBroadcastReceiver) ,

    упрощена работа с классом (не нужно помнить о регистрации и вызывать ее заранее) ,

    и самое главное - может получать getResultCode текущего ресивера (к примеру он нужен при получении статуса смс сообщения и в других случаях.). 

    unit BroadcastReceiver;
    
    interface
    
    {$IFDEF ANDROID}
    uses
      Androidapi.JNI.Embarcadero, Androidapi.JNI.GraphicsContentViewText, Androidapi.helpers,
      Androidapi.JNIBridge, FMX.Helpers.Android, Androidapi.JNI.JavaTypes,
      System.Classes, System.SysUtils;
    
    type
      TBroadcastReceiver = class;
    
      TListener = class(TJavaLocal, JFMXBroadcastReceiverListener)
      private
        fOwner: TBroadcastReceiver;
        fReceiver: JFMXBroadcastReceiver;
      public
        constructor Create(aOwner: TBroadcastReceiver);
        destructor Destroy; override;
        procedure onReceive(context: JContext; intent: JIntent); cdecl;
      end;
    
    
      TOnReceive = procedure (aContext: JContext; aIntent: JIntent; aResultCode: integer) of object;
    
      TBroadcastReceiver = class
      private
        fListener : TListener;
        fRegistered: boolean;
        fOnReceive: TOnReceive;
      public
        constructor Create(aOnReceiveProc: TOnReceive);
        destructor Destroy; override;
        procedure AddActions(const Args: array of JString);
        procedure SendBroadcast(const aValue: string);
      end;
    {$ENDIF}
    
    implementation
    
    {$IFDEF ANDROID}
    
    { TBroadcastReceiver }
    
    constructor TBroadcastReceiver.Create(aOnReceiveProc: TOnReceive);
    begin
      inherited Create;
      fListener := TListener.Create(Self);
      fOnReceive := aOnReceiveProc;
    end;
    
    destructor TBroadcastReceiver.Destroy;
    begin
      fListener.Free;
      inherited;
    end;
    
    procedure TBroadcastReceiver.AddActions(const Args: array of JString);
    var
      vFilter: JIntentFilter;
      i: Integer;
    begin
      if fRegistered then
        TAndroidHelper.context.getApplicationContext.UnregisterReceiver(fListener.fReceiver);
    
      vFilter := TJIntentFilter.JavaClass.init;
      for i := 0 to High(Args) do
        vFilter.addAction(Args[i]);
    
      TAndroidHelper.context.getApplicationContext.registerReceiver(fListener.fReceiver, vFilter);
      fRegistered := true;
    end;
    
    procedure TBroadcastReceiver.SendBroadcast(const aValue: string);
    var
      Inx: JIntent;
    begin
      Inx := TJIntent.Create;
      Inx.setAction(StringToJString(aValue));
      TAndroidHelper.Context.sendBroadcast(Inx);
    end;
    
    constructor TListener.Create(aOwner: TBroadcastReceiver);
    begin
      inherited Create;
      fOwner := aOwner;
      fReceiver := TJFMXBroadcastReceiver.JavaClass.init(Self);
    end;
    
    destructor TListener.Destroy;
    begin
      TAndroidHelper.context.getApplicationContext.unregisterReceiver(fReceiver);
      inherited;
    end;
    
    // usually android call it from "UI thread" - it's not main Delphi thread
    procedure TListener.onReceive(context: JContext; intent: JIntent);
    begin
      if Assigned(fOwner.fOnReceive) then
        fOwner.fOnReceive(Context, Intent, fReceiver.getResultCode);
    end;
    
    {$ENDIF}
    
    end.

     

    Как использовать

     

      // указывать нужно сразу все нужные вам Actions в Add через запятую, не по одной. 
      fBroadcast := TBroadcastReceiver.Create(OnReceiveBroadcast);
      fBroadcast.AddActions([StringToJString(SENT_ACTION)]); << Custom action
    -------------
      // или например сразу несколько Actions
      fBroadcast.AddActions([TJIntent.JavaClass.ACTION_SCREEN_OFF, TJIntent.JavaClass.ACTION_SCREEN_ON]);

     

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