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

serser

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

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

  • Посещение

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

  1. На самом деле нужно делать так:

    TJParcelable.Wrap((PendingIntent  as ILocalObject).GetObjectID)

    и

    TJPendingIntent.Wrap((Parcelable  as ILocalObject).GetObjectID)

    Но ожидаемого результата использования TAndroidHelper.Activity.createPendingResult не получилось. 

     

    После TMessageManager.DefaultManager.SubscribeToMessage(TMessageResultNotification, HandleActivityMessage);

    HandleActivityMessage  не получает результат из сервиса с помощью PendingIntent.send.

     

    Будь неладен тот день для ider-ы, когда я решил написать приложение с сервисом на дельфи,

    уже два месяца я не могу получить результат от сервиса:то

    1. createPendingResult  приложение не получает результат.

    2. для resultReceiver не хватает возможности получить результат в активити - переопределить onReceiveResult

     

    Остаются способы PendingResult.getAction и PendingResylt.getBroadcast.

    Первый способ (

    ) - уродский, уж извините, если закрыть приложение оно опять появится после ответа сервиса.

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

    Получается нельзя тут взрослое приложение-то сделать , только кошечек рисовать.

  2. 13 часов назад, mazayhin сказал:

    PIntent := JPendingIntent(Parcelable);

     

    Получается Segmentation fault

     PIntent  на момент присваивания = nil

    И это явно не простое присваивание, потому что во время него 10 раз в логе пишется switching thread, потом появляется эксепшн.

     

    Передаю интент в сервис так:

    class procedure TssAndroidServiceHelper.StartService(const AServiceName: string; AIntent: JIntent);
    var
      PendingIntent: JPendingIntent;
    begin
      PendingIntent := TAndroidHelper.Activity.createPendingResult(1, AIntent, 0);
    
      AIntent.setClassName(TAndroidHelper.Context.getPackageName(),
        TAndroidHelper.StringToJString(AServiceName));
    
      AIntent.putExtra(StringToJString('q'), JParcelable(PendingIntent));
    
      TAndroidHelper.Activity.startService(AIntent);
    end;

     

    Получаю так:

    TDM = class(TAndroidService)
        function AndroidServiceStartCommand(const Sender: TObject;
          const Intent: JIntent; Flags, StartId: Integer): Integer;
        procedure AndroidServiceCreate(Sender: TObject);
      private
        FPIntent: JPendingIntent;
        FStr: string;
        FThread: TssThread;
        procedure StartThread;
      public
        constructor Create(AOwner: TComponent); override;
        destructor Destroy; override;
      end;
    
    function TDM.AndroidServiceStartCommand(const Sender: TObject;
      const Intent: JIntent; Flags, StartId: Integer): Integer;
    var
      ResultIntent: JIntent;
      Parcelable: JParcelable;
    begin
      Parcelable := Intent.getParcelableExtra(StringToJString('q'));
      FPIntent := JPendingIntent(Parcelable);
    
      ResultIntent := TJIntent.Create;
      ResultIntent.putExtra(StringToJString('res'), StringToJString('content'));
      FPIntent.send(TAndroidHelper.Context, 7, ResultIntent);
    
      Result := TJService.JavaClass.START_STICKY;
    end;

     

    Есть еще идеи как вытащить отложенное намерение?

     

  3. Помогите достать JPendingIntent из JIntent.

    Пытаюсь из сервиса получить отложенный интент, созданный с помощью TAndroidHelper.Activity.createPendingResult.

     

    Делаю так:

    var

      Parcel: JParcelable;
      PIntent: JPendingIntent;

    begin

    Parcelable := Intent.getParcelableExtra(StringToJString('pendingintent'));

    PIntent := Parcelable ;

    ...

    end;

    Получается ошибка:

    E2010 Incompatible types: 'JPendingIntent' and 'JParcelable'

    Как приводить эти интерфейсы друг к другу?

     

  4.  

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

    Выходит, если мы рисуем на одной канве из двух потоков и у нас одновременно открыты в каждом Canvas.BeginScene, то после прорисовки по Canvas.EndScene на канве отобразиться суммарная картинка? 

     

     

    Исходя из реализации TCanvasGpu:

    function TCanvasGpu.DoBeginScene(const AClipRects: PClipRects; AContextHandle: THandle): Boolean;
    begin
      if FGlobalBeginScene = 0 then
      begin
        FCanvasHelper.SetContext(Context);
        FCanvasHelper.BeginRender;
        TTextLayoutNG.BeginRender;
      end
      else
      begin
        FCanvasHelper.Flush;
        FCanvasHelper.SetContext(Context);
    
        FContext.SetMatrix(TMatrix3D.Identity);
        FContext.SetContextState(TContextState.cs2DScene);
        FContext.SetContextState(TContextState.csAllFace);
        FContext.SetContextState(TContextState.csZWriteOff);
        FContext.SetContextState(TContextState.csZTestOff);
      end;
      Inc(FGlobalBeginScene);
      FSaveCanvas := FCurrentCanvas;
      if Assigned(FSaveCanvas) and FSaveCanvas.FClippingEnabled then
        FSavedScissorRect := FCanvasHelper.ScissorRect;
    
      FCurrentCanvas := Self;
    
      Result := inherited DoBeginScene(AClipRects) and Assigned(FContext) and FContext.BeginScene;
      if Result then
      begin
        FClippingEnabled := False;
        FCurrentClipRect := TRect.Create(0, 0, Width, Height);
        FCanvasHelper.ResetScissorRect;
        FCanvasHelper.UpdateDrawingMode;
      end;
    end;
    

    В частности из условия второго и последующих вхождений в DoBeginScene: if FGlobalBeginScene = 0 then ... else ...

    выходит, что если вошли второй раз, то происходит какой-то FCanvasHelper.Flush куда-то. Возможно и суммарная картинка отобразится. Надо пробовать.

     

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

  5. AlexG, спасибо за столь развернутый ответ =)

    Выходит, что в каком-то приближении отрисовку в FMX можно назвать потокобезопасной, но не многопоточной. Т.е. AV, как в VCL, не произойдет, но лаги быть могут.

  6. Ну вам выше вроде ответили, если не хотите лагов интерфейса то используюте синхронизацию

     

    Вы про ALOOPER_POLL_ERROR на андроиде? Да, видимо андроид сам ограничивает этот процесс и мы никогда не узнаем, что будет, если эту проверку в нем убрать. Но что будет происходить на других платформах? На windows и mac os x я не заметил никаких глюков. Может быть при интенсивной отрисовке и будут артефакты (наподобие тех, когда отключаешь вертикальную синхронизацию в играх или двойную буферизацию на компоненте на форме), но их, наверное, можно избежать - например, один поток рисует на одной половине, другой на другой.

    Кто-нибудь сталкивался с более фатальными ошибками при отрисовке из НЕглавного потока без синхронизации?

  7. Спасибо, интересные подробности про андроид и яву. Я пока только под настольный mac os x пробую и только с контролами FMX.

     

    Если же вы работаете с FMX графикой, до достаточно выполнять обычный TThread.Synchronize и Queen

    Собственно про это и вопрос - а нужно ли? Времена VCL-ной однопоточной отрисовки в этом случае прошли. Вся начинка FMX уже другая. Так вот Может я хочу свой (не главный) поток для отрисовки. Или может быть даже два потока. А не синхронизировать все через TThread.Synchronize. Поэтому и спрашиваю, можно ли так?)

  8. Всем известно, что используя Vcl под Windows нельзя делать делать отрисовку не из главного потока ввиду особенностей канвы и vcl в целом.

    Как ведет себя Firemonkey в этом случае на разных платформах? Может уже можно делать эти вещи из других потоков?

    (опустим то, что это может привести к размазанности логики отрисовки).

     

    Пробовал манипулировать ProgressBar-ом из потока - вроде никаких ошибок не было.

     

    Нашел ответ от Brovin Yaroslav,

     

    Вся отрисовка выполняется в отдельном потоке (известный как UI Thread), из других потоков рисовать в нем запрещено. При попытке это сделать, вы получите исключение. На андроиде оно несет название "ALOOPER_POLL_ERROR". На других платформах будет немного другой текст ошибки.  Чтобы отрисовка происходила в главном потоке (UI Thread) нужно добавить синхронизацию потоков через 

    TThread.Synchronize

    или 

    TThread.Queen

     

    Получается под андроидом это в порядке вещей или  UI Thread = Main Thread?

  9. Нет-нет, сейчас проверил. Связывается только по имени всех параметров, кроме первого и по имени метода. Причем попробовал тип WebFrame в объявлении заменить на NSURL и делегат все равно вызвался. Спасибо)

  10. О чудо! Оно работает) Спасибо, Ярослав!

     

    Я думал, что связывание происходит только по имени метода.

     

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

    Первый параметр (webView1 для которого, кстати, не важно имя) является Self-ом, который передается неявно в ObjC, но у нас он выделен явно? В этом случае можно ли использовать дельфевый Self? (Скорее всего можно, но все же)

     

    Все-таки что означает первая часть определения, до имени метода:

    - (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id < WebPolicyDecisionListener>)listener

    То, что webView является первым параметром, а webView: началом имени или есть какой-то еще смысл?

  11. Помогите портировать интерфейсы для реализации делегата для WebView.setPolicyDelegate, с помощью которого можно запрещать или переопределять переходы по ссылкам.
    Отталкивался от хелпа эпла. Реализовал вроде как все, что нужно. Страница гугла открывается, но колбэк делегата не вызывается.

    unit MainFormUnit;
    
    interface
    
    uses
      System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
      FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
    
      Macapi.AppKit,
      Macapi.CocoaTypes,
      Macapi.Foundation,
      Macapi.ObjectiveC, FMX.StdCtrls,
    
      Posix.Stdlib, Macapi.CoreFoundation, FMX.Platform.Mac,
      System.Generics.Collections;
    
    type
      WebFrameClass = interface(NSObjectClass)
      ['{7BE750C8-DFEC-4870-851A-12DBCB0B78F6}']
      end;
    
      WebFrame = interface(NSObject)
      ['{BCFA04BE-41AB-4B78-89C0-3330F12C7695}']
        procedure loadRequest(request: NSURLRequest); cdecl;
      end;
    
      TWebFrame = class(TOCGenericImport<WebFrameClass, WebFrame>)
      end;
    
      WebViewClass = interface(NSViewClass)
      ['{0D9F44B7-09FD-4E35-B96E-8DB71B9A2537}']
        {class} function canShowMIMEType(MIMEType: NSString): Boolean; cdecl;
      end;
    
      WebView = interface(NSView)
      ['{C36D8016-2FCB-49F0-BA1C-C9913A37F9AC}']
        procedure clos; cdecl;
        procedure setPolicyDelegate(delegate: Pointer); cdecl;
        procedure setHostWindow(hostWindow: NSWindow); cdecl;
        function initWithFrame(frame: NSRect; frameName: NSString; groupName: NSString): Pointer; cdecl;
        function mainFrame: WebFrame; cdecl;
      end;
    
      TWebView = class(TOCGenericImport<WebViewClass, WebView>)
      end;
    
      WebPolicyDecisionListener = interface(IObjectiveC)
      ['{2AD8355D-6C57-410D-A4F4-230C90B6D799}']
        procedure download; cdecl;
        procedure ignore; cdecl;
        procedure use; cdecl;
      end;
    
      WebViewDelegate = interface(IObjectiveC)
      ['{5B66FF5F-DA92-48D3-A715-C89A68AA8995}']
        procedure decidePolicyForNavigationAction(actionInformation: NSDictionary;
          request: NSURLRequest; frame: WebFrame; listener: WebPolicyDecisionListener); cdecl;
      end;
    
      TWebViewDelegate = class(TOCLocal, WebViewDelegate)
        procedure decidePolicyForNavigationAction(actionInformation: NSDictionary;
          request: NSURLRequest; frame: WebFrame; listener: WebPolicyDecisionListener); cdecl;
      end;
    
      TForm1 = class(TForm)
        Button1: TButton;
        procedure FormCreate(Sender: TObject);
      public
        MyWebView: WebView;
        MyDelegate: TWebViewDelegate;
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.fmx}
    
    procedure TForm1.FormCreate(Sender: TObject);
    var
      PWebView: Pointer;
      FwkMod: HMODULE;
      urlStr: NSURL;
      urlreq: NSURLRequest;
    
      MyView: NSView;
    const
      WebKitFWK: string = '/System/Library/Frameworks/WebKit.framework/WebKit';
    begin
      FwkMod := System.SysUtils.LoadLibrary(PWideChar(WebKitFWK));
      PWebView := TWebView.Alloc.initWithFrame(MakeNSRect(10, 10, 500, 500), nil, nil);
      MyWebView := TWebView.Wrap(PWebView);
      MyWebView.setAutoresizingMask(NSViewHeightSizable or NSViewWidthSizable);
      //MyWebView.setHostWindow(MyNSWindow);
    
      MyView := WindowHandleToPlatform(Form1.Handle).View;
    
      MyView.addSubview(MyWebView);
    
      MyDelegate := TWebViewDelegate.Create;
      MyWebView.setPolicyDelegate((MyDelegate as ILocalObject).GetObjectID);
    
      urlStr := TNSURL.Wrap(TNSURL.Alloc.initWithString(NSSTR('http://www.google.com/')));
      urlreq := TNSURLRequest.Wrap(TNSURLRequest.Alloc.initWithURL(urlstr));
      MyWebView.mainFrame.loadRequest(urlreq);
    
      urlStr.release;
      urlreq.release;
    end;
    
    { TWebViewDelegate }
    
    procedure TWebViewDelegate.decidePolicyForNavigationAction(
      actionInformation: NSDictionary; request: NSURLRequest; frame: WebFrame;
      listener: WebPolicyDecisionListener);
    begin
      MessageDlg('hi', TMsgDlgType.mtInformation, [TMsgDlgBtn.mbOK], 0);
    end;
    
    end.
    
    

    Также не совсем понятно, где должен располагаться метод webView:decidePolicyForNavigationAction:request:frame:decisionListener. В документации он объявлен как:

    - (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id < WebPolicyDecisionListener>)listener

    Т.е. похоже на то, что он должен быть методом класса WebView? Или же методом произвольного класса делегата?

     

    И еще, я так понимаю, что полное имя этого метода webView:decidePolicyForNavigationAction:request:frame:decisionListener, то есть объявляя его как decidePolicyForNavigationAction возможно мы лишаем mac os возможности найти его. Но как же тогда объявить его полностью?

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