Перейти к содержанию
  • Регистрация
  • 0
notricky

Form.Show в потоке. (called from wrong thread exception)

Вопрос

На Android код, который работает исправно на Win  вызывает ошибку "CalledFromWrongThreadException: Only the original thread that created a view hierarcy can touch its views" 

Смысл таков, что я пытаюсь показать форму из треда, у которой BorderStyle=none (роли это не играет).

Решение в Андроиде заключается в том, чтобы пускать через  runOnUiThread  (то есть выполнять интерфейсные штуки в главном потоке). Как я понимаю, в firemonkey эту фичу должен выполнять Synchronize().
Тем не менее, ошибка возникает.
А при запуске в режиме дебага на андроид девайсе событие кнопки вообще не срабатывает иногда. А если срабатывает, то возникает описанное выше исключение.
Я собрал тестовый пример и в нем не сразу видна ошибка, тогда как получил я ее на рабочем проекте.
Цель: показать бизибокс на время бекграундных действий. Этот бизибокс у меня сначала был просто на каждой форме и я интерфейсно его вызывал, но теперь решил сделать отедльной формой (как и тоаст), но почему так происходит я не понял. Вы что скажете?

 

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
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TWorkThread = class(TThread)
  public
    procedure Execute; override;
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

uses unit2;

procedure TForm1.Button1Click(Sender: TObject);
var t: TWorkThread;
begin
  t := TWorkThread.Create(True);
  t.FreeOnTerminate := true;
  t.Start;
end;

{ TWorkThread }

procedure TWorkThread.Execute;
begin
  inherited;
  Self.Synchronize(procedure 
  begin
    Form2.Show; 
	Form2.Top := Form1.Top; 
	Form2.Left := Form1.Left;
    Form2.BringToFront;
  end);
  Terminate;
end;

end.

 

Изменено пользователем notricky

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


Ссылка на сообщение
Поделиться на другие сайты

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

  • 0

Почему так - скажут знатоки андроида. Емнип, UIThread != MainThread (пока еще)

А вообще - посоветую взять из fgx ActivityDialog

Изменено пользователем kami

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
7 часов назад, kami сказал:

Почему так - скажут знатоки андроида. Емнип, UIThread != MainThread (пока еще)

А вообще - посоветую взять из fgx ActivityDialog

Да, в комментах на Stackoverflow выяснили это с Remy Lebeau.

Решение - IFDEF-ить для андроида моменты синхронизации интерфейса через FMX.Platform.Android.TPlatformAndroid
Пока не проверял, но looking forward to :)
Если кто попробует и отпишется, будет классно всем на будущее.

fgx ActivityDialog
Не сочтите за наглость, O-kami :),  но если вкратце, то это про что?

Изменено пользователем notricky

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
7 часов назад, krapotkin сказал:

поднимаемся до начала страницы

находим закладку FGX

Посмотрел. 

Этокак я понял компонент и его надо класть на каждую форму. У меня другая задача - форму-бизибокс сделать. Но за хинт спасибо. 

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
1 час назад, notricky сказал:

Этокак я понял компонент и его надо класть на каждую форму.

вот именно, что это - компонент, а не контрол. И его достаточно иметь в любом "общем" модуле, возможно - даже создать в runtime. В общем, его достаточно иметь в одном экземпляре. Но - дело ваше.

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
3 часа назад, kami сказал:

вот именно, что это - компонент, а не контрол. И его достаточно иметь в любом "общем" модуле, возможно - даже создать в runtime. В общем, его достаточно иметь в одном экземпляре. Но - дело ваше.

А у него таких проблем с отрисовкой/показом нет/решены?

А стилизацию/настройку цветов, прозрачности имеет?

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Если кто зайдёт настолько далеко, то решение кроется в FMX.Helpers.AndroidCallInUIThreadAndWaitFinishing

{$IFDEF}  в нужных местах делает своё дело. Не смотрел внутрь компонентов FGX, может быть там сделано кросплатформеннее?

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Нет, похоже и этот метод какой-то багонутый.

Последовательность внутри потока

    {$IFDEF ANDROID}
    CallInUIThreadAndWaitFinishing(ShowOverlay);
    Sleep(1000);
    CallInUIThreadAndWaitFinishing(ShowForm);
    Sleep(1000);
    CallInUIThreadAndWaitFinishing(HideOverlay);
    {$ELSE}

не всегда заканчивается тем, что HideOverlay реально хайдит оверлейную форму. То есть да, в метод хайда заходит (анимация останавливается), но непосредственно сам хайд окна заканчивается одним из трех вариантов, при том рандомно:

  • Анимация заморожена, окно висит
  • Окно скрыто, видны какие-то артефакты
  • Окно скрыто штатно

Ни в варианте прямого вызова Overlay.Hide

Ни в варианте TMessageSender.SendMessage().

Интересно вообще в чем именно заключается баг. Баг ли это или это нормальная работа Андроида...

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
8 часов назад, notricky сказал:

Буду признателен, если кто-то что-то по этому поводу скажет.

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

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
2 часа назад, Brovin Yaroslav сказал:

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

Я честно не понял. Ведь даже в нативном коде такой вызов является правильным решением. Разве CallInUIThread не выполняет код внтури основного (всмысле интерфейсного) потока?

И второй вопрос - пишут, что до ХЕ7 нужно было выполнять в таймере  CheckSync чтобы прокачивать очередь. Начиная с ХЕ7 пишут что пофиксен баг. Получается что SendMessage из рабочего потока в окна, созданные главным потоком должны правильно обрабатываться. Или тоже есть какие-то интересные особенности?

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Ну то есть когда я в рабочем потоке делаю так:

var
  Form1: TForm1;
  MsgSender: TMessageSender;

procedure TWorkThread.ShowOverlay;
var V: Tvalue;
begin
  V := Tvalue.From(Form1.RectSelf);
  MsgSender.Receiver := TFOverlay.This;
  MsgSender.SendMessageWithResult(PM_OVERLAY_SHOW, V);
end;

...
procedure TWorkThread.Execute;
begin
  try
    ShowOverlay;
    Sleep(1000);
    HideOverlay;
  except
    on e: exception do MessageDlg(e.Message,TMsgDlgType.mtWarning, [TMsgDlgBtn.mbYes], 0, nil);
  end;
  Terminate;
end;


// OVERLAY
....
type
  TFOverlay = class(TForm)
    procedure PMShow(var AMessage: TDispatchMessageWithValue<TRect>); message PM_OVERLAY_SHOW;
  ...
  end;
      
implementation

procedure TFOverlay.PMShow(var AMessage: TDispatchMessageWithValue<TRect>);
begin
  FRect := AMessage.Value;
  This.Show;
end;

тем не менее я получаю ошибку  CalledFromWrongThreadException: Only the original thread that created a view hierarcy can touch its views" 

На самом деле если внутри рабочего потока ShowOverlay обернуть в CallInUIThread то ошибки нет, но, как описал Ярослав, негарантированно.

замкнутый круг. Хочу понять что не так и как вообще следует проектировать в ХЕ8 интерфейсы.

 

Изменено пользователем notricky

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0

FMX, также как и VCL так же как и вообще все объекты (за исключением некоторых специальных) не потокобезопасны. Т.е. напрямую использовать в потоке что-либо созданное вне этого потока нельзя, потому, что нельзя никогда... Всякие там формы кнопки и пр. взаимодействуют с другими формами кнопками и пр. контролами, так что даже если вы создаете и уничтожаете форму внутри потока (внутри метода Execute), то всё равно не явно Вы обращаетесь к другим объектам системы. Чтобы решить эту проблему все обращения к контролам надо делать в методе  Synchronize По этому ключевому слову ищите информацию в интернете и изучайте многопоточность.

Но лучше просто не работайте с интерфейсом в потоке. В этом примере можно просто устанавливать и сбрасывать некий флаг FOverlayShown. К нему Вы можете обращаться из основного потока в любой момент (к FErrorMessage только после окончания работы потока). Обрабатывать OverlayShown можно например событии TAction.OnUpdate или хотя бы в TTimer.

procedure TWorkThread.Execute;
begin
  try
    FOverlayShown := True;
    try
      Sleep(1000);
    finally
      FOverlayShown := False;
    end;
  except
    on e: exception do
    begin
      FErrorMessage := e.Message;
    end;
  end;
end;

P.S. А лучше вообще не связывайтесь с потоками.

Изменено пользователем RoschinSpb

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
1 час назад, RoschinSpb сказал:

FMX, также как и VCL так же как и вообще все объекты (за исключением некоторых специальных) не потокобезопасны. Т.е. напрямую использовать в потоке что-либо созданное вне этого потока нельзя, потому, что нельзя никогда... Всякие там формы кнопки и пр. взаимодействуют с другими формами кнопками и пр. контролами, так что даже если вы создаете и уничтожаете форму внутри потока (внутри метода Execute), то всё равно не явно Вы обращаетесь к другим объектам системы. Чтобы решить эту проблему все обращения к контролам надо делать в методе  Synchronize По этому ключевому слову ищите информацию в интернете и изучайте многопоточность.

Но лучше просто не работайте с интерфейсом в потоке. В этом примере можно просто устанавливать и сбрасывать некий флаг FOverlayShown. К нему Вы можете обращаться из основного потока в любой момент (к FErrorMessage только после окончания работы потока). Обрабатывать OverlayShown можно например событии TAction.OnUpdate или хотя бы в TTimer.


procedure TWorkThread.Execute;
begin
  try
    FOverlayShown := True;
    try
      Sleep(1000);
    finally
      FOverlayShown := False;
    end;
  except
    on e: exception do
    begin
      FErrorMessage := e.Message;
    end;
  end;
end;

P.S. А лучше вообще не связывайтесь с потоками.

Зачем читать тему целиком, когда можно просто в белом выйти.

Ну ладно, не прочитали. Бывает.
Ответите тогда на вопрос - почему возникает поднятая проблема (да, для этого надо тему почитать) в случае с посылом сообщений классу формы из потока?

Изменено пользователем notricky

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
21 час назад, notricky сказал:

SendMessageWithResult

SendMessage через механизмы FMX !=SendMessage через механизмы Windows. Да, в Windows получатель обработает сообщение в том потоке, в котором принявшее сообщение окно было создано. Боюсь, что SendMessage из FMX не учитывает это, так что прием сообщения осуществляется в контексте вызывающего потока. Со всеми вытекающими.

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
13 часов назад, kami сказал:

SendMessage через механизмы FMX !=SendMessage через механизмы Windows. Да, в Windows получатель обработает сообщение в том потоке, в котором принявшее сообщение окно было создано. Боюсь, что SendMessage из FMX не учитывает это, так что прием сообщения осуществляется в контексте вызывающего потока. Со всеми вытекающими.

Глупость какая-то. Всмысле реализация - теряется весь смысл сообщений, в особенности если это сообщения на отрисовку. А где-то про это вообще написано?

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
19 минут назад, notricky сказал:

А где-то про это вообще написано?

Я искал (перед тем, как написать предыдущее сообщение) - не нашел.

Посему - мой предыдущий пост написан именно на основе собственных умозаключений. В частности:

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

В FMX сообщения отправляются объекту. Объект - существо интернациональное, оно существует без привязки к какому-нибудь потоку, а некоторые - так вообще не могут существовать в пределах одного (TThread).

Собственно, именно поэтому я и пришел к выводу, что раз нельзя определить, в каком потоке сообщение должно быть принято объектом, значит всё происходит именно в текущем.

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
2 часа назад, kami сказал:

Я искал (перед тем, как написать предыдущее сообщение) - не нашел.

Я наткнулся на такую тему:
Оконные сообщения в FireMonkey

Правда про потоки там ни слова... Зато в коментах Ярослав Бровин присутствует :)

Изменено пользователем notricky

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0

А знаете что я вам скажу?? А вот угадайте, в чем была на самом деле проблема???

А проблема была как всегда у Эмбаркадеро неявная, а именно в том, что BorderStyle = bsNone не дружит с вызовами вооообще. Ниоткуда. И вызывает вышеобозначенную ошибку в любом из возможных вариантов. И треды тут вообще не при чем. Ну то есть вот совсем не при чем. То есть если правильно задать BorderStyle, то вполне можно обойтись на Android оборачиванием вызовов Show/Hide TThread.Queue(...)

Часы.... просто часы тестов убиты на такой маразм.

Друзья, коллеги, если у вас есть последняя версия FMX, пожалуйста, протестируйте этот вариант с Бордером на андроиде. И отпишитесь здесь. И если это баг, то может быть стоит репортнуть. Для теста нужно две формы, одна из которых обычная, вторая borderStyle=None и вызывается кнопкой из первой формы. Обе создаются обычным способом при инициализации приложения.

Upd2:

Еще одно замечание.
Если выставлено bsNone, но при этом FullScreen = True, то другие формы открываются обычным Form.Show ровно до того момента, как было обращение на показ формы с bsNone и FullScreen = True. После этого последняя показывается, а вот все прочие формы, открывающиеся по кнопке обычным образом уже идут с ошибками  CalledFromWrongThreadException: Only the o....

Изменено пользователем notricky

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
В 26.01.2017 в 21:27, notricky сказал:

Зачем читать тему целиком, когда можно просто в белом выйти.

Да, действительно всю тему не прочитал, виноват. Вы тогда про 

    FOverlayShown := True;
    try
      Sleep(1000);
    finally
      FOverlayShown := False;
    end;

тоже не читайте, ибо малодушный поиск лёгких путей — это не спортивно ;)

Посыл сообщений физически это просто вызов некоторого метода объекта, только в отличие от обычных методов обработчики сообщений могут существовать, или не существовать. Смысл посыла сообщений в том, чтобы избавится от зависимостей, т.е. отправитель может не знать какие конкретно методы есть у получателя. Все ограничения связанные с многопоточностью остаются в силе. Главное ограничение это то, что нельзя работать с любыми интерфейсными элементами внутри потока без использования Sinchronize. Если с Sinchronize не работает, то надо написать об ошибке в QC, надеяться и ждать.

Изменено пользователем RoschinSpb

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
13 часов назад, RoschinSpb сказал:

Да, действительно всю тему не прочитал, виноват. Вы тогда про 


    FOverlayShown := True;
    try
      Sleep(1000);
    finally
      FOverlayShown := False;
    end;

тоже не читайте, ибо малодушный поиск лёгких путей — это не спортивно ;)

Посыл сообщений физически это просто вызов некоторого метода объекта, только в отличие от обычных методов обработчики сообщений могут существовать, или не существовать. Смысл посыла сообщений в том, чтобы избавится от зависимостей, т.е. отправитель может не знать какие конкретно методы есть у получателя. Все ограничения связанные с многопоточностью остаются в силе. Главное ограничение это то, что нельзя работать с любыми интерфейсными элементами внутри потока без использования Sinchronize. Если с Sinchronize не работает, то надо написать об ошибке в QC, надеяться и ждать.

Все оказалось куда хуже. И сообщения работают, и синхронайз, только вот проблема была в BorderStyle. Почитайте два сообщения назад. И вот это возможно репорт для QC, если у кого-то еще такая же ситуация на новых дельфях возникает. Но пока никто не отписался.

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Еще один странный баг, если кому интересно и кто знает что то про это.

 

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

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0

Пока что решение такое: перед хайдом формы найти и активировать следующую активную форму (ту, вероятно, что под оверлеем)

 Screen.NextActiveForm(OverlayForm).Activate;

Внутри синхрониза естественно.

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


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

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

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

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

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

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


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

    • От Игорь Маринин
      поделитесь пожалуйста пустым проектом, готовым к публикации для TV устройств.
      что-то никак не получается опубликовать, сейчас отклонили с такими ошибками:
      APK:8
      No Now Playing notification [card]"
      Your App does not contain a “Now Playing” notification [card] for when the user has selected the HOME button within the app. Please refer to our Displaying a Now Playing Card documentation for more details.
      APK:8
      Play/Pause key event is not respected during playback
      Your media apps that play video or music content must respect the play/pause key during playback. Please refer to our Media Play/Pause documentation and Update the Playback State documentation for details.
      Missing DPad functionality
      Your app requires user interaction for menus or app navigation. Please make sure that all menus and app navigation are fully functional using a DPad. Please refer to our DPAD Control and Hardware Declaration documentation.
      ну и баннер не прилепил
      No full-size app banner
      Your app does not contain a full-size app banner or is it not visible in the launcher. We are targeting 1080P, which we consider xhdpi. Apps should include the banner in the xhdpi (320 dpi) drawables folder with a size of (320px × 180px). Please refer to our Home Screen Banner and UI Patterns documentation.
      The title should help users identify apps in the launcher. Please refer to our Visual Design and User Interaction documentation for more information.
      был бы очень благодарен за рабочий пустой костяк с манифестом.
       
    • От krapotkin
      В процессе разработки столкнулся с очень странной ситуацией, корни которой до сих пор неясны, но решение нашлось.
      Итак. Делфи 10.3.3. Чистое приложение - пустая форма и кнопка. Отлично работает на разных устройствах кроме Samsung Galaxy Tab A (2016). Android 5.1.1
      Программа падает, не успев даже загрузиться. Любая. При этом она же, скомпилированная на другом компе, запускается нормально. И даже после изменения SDK/NDK на нем, ничего не падает.
      LogCat дает крайне странную картину
      java.lang.IllegalArgumentException: Unable to load native library: /data/app-lib/com.embarcadero.Project1-1/libProject1.so
      Начинаем экспериментировать с SDK, NDK и т.д. Поставил также хотфиксы для 10.3.3.
      Сразу скажу, SDK/NDK ставились отдельно через Android studio, не скачивались вместе с Delphi. Не торопитесь бросать чтение на этом месте!)) На другом компе, где все работает, все ставилось точно так же.
      Короче, очень много комбинаций версий SDK/NDK проверено.
      Результат такой. При постепенном понижении версии NDK все взлетело при NDK v22.

      При этом версия SDK видимо такого большого влияния не имеет, потому что этот вариант нормально работает

      Повторюсь. На других устройствах все работало и на более новых Ndk. Xiaomi Mi Pad4 , Samsung Galaxy Tab A (2019), Xiaomi Redmi 5 и 5Plus
       
      Спасибо за участие и помощь в разборе завалов @Andrey Efimov
       
    • От krapotkin
      У меня в работе два приложения, и оба они не предназначены для Play market, так как имеют ограниченный круг использования, по сути, чисто внутрикорпоративные. Так что нежелательно и выкладывание их и на альтернативные магазины приложений. 
      Автоматически возникает вопрос обновления. Если в  первый раз мы можем установить приложение сами при помощи админов, то обновлять их не так просто. А контингент пользователей не справится с "скачайте APK по ссылке, найдите, куда его скачал браузер, и запустите вручную именно последний скачанный, а не какой попало"...
      Простейший способ - дать приложению скачать свежую копию с сайта и натравить на полученный файл системный инсталлер.
      Вот только свежие Andoird делать это напрямик запрещают. Нужен filepropvider. Целый день шуровал по мануалам и YT,
      Вот то что получилось  в результате.
      Если у вас 10.3.3 как у меня, уже можно не вносить <provider>...</provider> в манифест и свой файл file_paths.xml (или как вам его советуют назвать в интернетах) в деплой.
      Теперь все это делается хоть несколько странно и однобоко, но автоматически, путем установки галочки Secure File Sharing

      после этого в манифесте автоматически пропишется один из вариантов размещения файлов, которые вы можете найти в интернете. Используется алиас external-path
      файл, показанный на рисунке, создается автоматически самой делфи.

      теперь остается отгадать, какой путь реально подставится вместо "."
      Как показала практика, все пути выглядят не так, как кажется, если исходить из простого здравого смысла. Целый день использования GetHomeDir и других полезных методов TPath завел меня совсем в тупик.
      Оказалось все проще (?)
      st:TMemoryStream; OutputDir: JFile; ApkFile: JFile; ApkUri: Jnet_Uri; path, filename: string; ... OutputDir := TAndroidHelper.Context.getExternalCacheDir(); path := JStringToString(OutputDir.getAbsolutePath); filename := path+'/ASDroid2.apk'; ApkFile := TJfile.JavaClass.init( StringToJstring(filename)); FApkUri := TAndroidHelper.JFileToJURI(ApkFile); st.Position := 0; st.SaveToFile(filename); обратите внимание, в provider_paths мы задаем external-paths, а в коде ищем ExternalCacheDir.!!!  (For.Unbelievably.Creative.Knowers!)
      Потом все просто. FApkUri передаем в интент и запускаем 
      итоговый код примерно таков. (скачивание в потоке с использованием небольшого собственного API, но там ничего важного, можно не обращать внимания)
      procedure TasdSettingsFrame.bDownloadClick(Sender: TObject); begin {$IFDEF ANDROID} bDownload.Enabled := False; DownloadAndRun(); {$ENDIF} end; {$IFDEF ANDROID} procedure TasdSettingsFrame.DownloadAndRun(); begin ttask.Run(procedure var aapi:TasdAPI; st:TMemoryStream; OutputDir: JFile; ApkFile: JFile; ApkUri: Jnet_Uri; path, filename: string; begin st := TMemoryStream.Create; aapi := TasdAPI.Clone(_API); try aapi.OnReceiveData := OnReceiveData; aapi.getApk(st); if aapi.Err.Code=0 then begin OutputDir := TAndroidHelper.Context.getExternalCacheDir(); path := JStringToString(OutputDir.getAbsolutePath); filename := path+'/ASDroid2.apk'; ApkFile := TJfile.JavaClass.init( StringToJstring(filename)); FApkUri := TAndroidHelper.JFileToJURI(ApkFile); st.Position := 0; st.SaveToFile(filename); TThread.Synchronize(nil,procedure begin bDownload.Enabled := true; StartActivity(FApkUri); end); end; finally st.Free; aapi.Free; end; end); end; procedure StartActivity(ApkUri: Jnet_Uri); var Intent: JIntent; begin Intent := TJIntent.Create(); Intent.setAction(TJIntent.JavaClass.ACTION_VIEW); Intent.addFlags(TJIntent.JavaClass.FLAG_ACTIVITY_NEW_TASK or TJIntent.JavaClass.FLAG_ACTIVITY_CLEAR_TOP or TJIntent.JavaClass.FLAG_GRANT_WRITE_URI_PERMISSION or TJIntent.JavaClass.FLAG_GRANT_READ_URI_PERMISSION); Intent.setDataAndType(apkuri, StringToJString('application/vnd.android.package-archive')); TAndroidHelper.Activity.startActivity(Intent); end; procedure TasdSettingsFrame.OnReceiveData(const Sender: TObject; AContentLength: Int64; AReadCount: Int64; var Abort: Boolean); begin tthread.Synchronize(nil, procedure begin pb1.Max := AContentLength; pb1.Value := AReadCount; end); end; {$ENDIF} Вопросы остались конечно, почему так странно с каталогами, но выяснять пока нет желания. Работает - не трожь.
      Всем удачи.
      UPD.
      Для того, чтобы системный инсталлер запускался, нужно не забыть отметить еще одну галочку

       
       
       
       
       
    • От Дмитрий Потапов
      Приветствую. На просторах интернета нашел BASS-библиотеку для Android и соответственно обертку для нее под Delphi.

      Вроде бы все работает нормально, но вот при настройке библиотеки при помощи методов
      BASS_GetConfigPtr, BASS_SetConfigPtr для работы со строковыми параметрами возникает проблема.
      На Windows с этим я легко работал, там достаточно использовать такую конструкцию

       
      PAnsiChar(BASS_GetConfigPtr(configId)) и получаем значение. BASS_SetConfigPtr(configId, PAnsiChar(value)) и задаем значение. Но вот под Android такой способ не проходит, как минимум по одной причине - он не понимает, что такое PAnsiChar. На docwiki.emarcadero.com, есть вот такая статейка. В которой написано, что PAnsiChar нужно заменить одним из трех: System.String, System.MarshalledString или System.SysUtils.TStringBuiler
      Только вот, если использовать MarshalledString, то при попытке получить значение приложение просто намертво зависает и все.
      Потом я подумал, так как библиотека написана на Java (вероятно), то может стоит попробовать использовать JNI в работе с ней, так как в Java файле, который прилагался вместе с библиотекой. Там я нашел объявления этих функций и заметил, что тип возвращаемого значения Object (ну, не зная Java я просто предположил, что это тоже просто ссылка на значение, например как PAnsiChar в Delphi на Windows).

      Но, при попытке как-либо использовать это натыкаюсь на проблемы в виде ошибки компиляции, либо очередном зависании приложения.
      Так как возвращается Object, то решил попробовать вариант с JObject и JString, но ни один вариант не хочет работать, опять ошибки на стадии компиляции, либо зависание приложение. Может быть, я что-то не так делаю.

      В общем, буду признателен за помощь!
    • От Yarpda
      Доброго времени!
      Есть идея сделать возможность резервирования данных приложения на Google drive под текущим аккаунтом пользователя. Ничего подобного я на форуме не нашел, может быть кто-то уже пытался решать подобную задачу? Интересует работа с Gdrive  в первую очередь.
    • От Ali Ezzeddine
      65/5000       Уважаемые,
      Есть ли способ вызвать сервис Java из приложения Delphi FMX?
    • От Эрик Шакиров
      Привет всем! Кто нибудь может подсказать как реализовать анимацию переходов между формами в Android без использования TabControl? Или подсказать в какую сторону "рыть"
    • От Светлана
      Ну всё в принципе как всегда, либо я барашка, либо лыжи не едут)
      А всё просто - я хочу, чтобы пока данные с сервера загружались по клику кнопки, пользователю элементарно был отклик в виде крутящейся какой нибудь фигни и он видел, что процесс идёт и что прога не зависла и никуда лишний раз не тыкал.
      Пока что для тестов сделала элементарно кнопку Update (speedbutton с image), данные элементарно грузятся и отображаются в GridPanel, а поверх него, чтоб пользователь и не смог куда либо тыкнуть, замостила панелькой с Image, вращаемой по таймеру (всё это дело наверху Visible:=false). И когда клацаем по кнопке Update, то панельку сверху грида делаю отображаемой и запускаю таймер, потом этот же обработчик/процедура грузит данные, а по окончанию останавливаем таймер и скрываем полупрозрачну, еще кстати, панельку. Аля вот так:
      procedure TForm1.SB_DataUpdateClick(Sender: TObject); begin //отображаем лого загрузки P_showLoad.Visible := true; Timer_load_rotate.Enabled := true; //с запуском таймера GetDeD_List(DE_set.Date); //процедура загрузки и отображения чего нам надо, которая весьма долго выполняется //и скрывае лого загрузки Timer_load_rotate.Enabled := false; //уже в обратном порядке P_showLoad.Visible := false; end; иии... ни черта не происходит как я хочу(
      Это лого вообще в итоге не отображается, а если убрать его скрытие, то оно у нас отобразится уже только тогда, когда всё загрузится. Логика мне стала подсказывать, что следовало его как то отобразить выполнив в параллельном асинхронном потоке аля так:
      procedure TForm1.SB_DataUpdateClick(Sender: TObject); begin TThread.Queue(TThread.Current, //TThread.Queue TThread.Synchronize ForceQueue procedure() begin P_showLoad.Visible := true; Timer_load_rotate.Enabled := true; end); GetDeD_List(DE_set.Date); //процедура загрузки и отображения чего нам надо, которая весьма долго выполняется end; И опять оно отображается только после того, как всё загрузится и проработает вся процедура. И уже чего только не пробовала и Synchronize и ForceQueue; и через TTask.Run и |task := TTask.Create(procedure () ... и т.д.| ничего не подходит, вот хоть убейся это всё дело будет отображаться только после полной отработки процедуры клика. Может я не в том направлении вообще рою и это как то по другому делается? Может я еще пока отлаживаю на Win32, а не всё на android, а там вот пара вариантов и норм на нём работают? Но чтот я никак не могу понять, что к чему... должно же быть как то просто, а я чтот никак не могу понять как(
    • От ComAlex
      Goоgle Play перестает поддерживать 32-bit Android-приложения c 01.08.2019.
      А выкладывать в Goоgle Play новые УЖЕ нельзя.
      Последние же Delphi XE не позволяют создать 64-bit Android-приложения.
      Кто знает, когда появится новая версия с поддержкой 64 - bit? Говорили, что в конце лета, но лето кончилось
    • От ComAlex
      Здравствуйте, господа программисты!
      Пытаюсь протестировать Android приложение на любом эмуляторе.
      Всегда одна ошибка "Unable to create process: Performing Streamed Install"
      Понимаю, что ссылок много по данной теме в интернете, но ни одна не помогла.
      Использую Embarsadero Delphi 10.3
      При компиляции на реальный телефон всё работает
      При компиляции на эмулятор даже пустого приложения выдается та же ошибка
      "Unable to create process: Performing Streamed Install"
      В чем проблема? Хотя бы в какую сторону копать?
  • Последние посетители   0 пользователей онлайн

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

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