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

Переезд на 10.3 Rio


gonzales

Вопрос

Доброго времени суток!

Возникла необходимость переехать на 10.3 (дабы поддерживались пуши на устройствах с андроид8 ну и вообще) 

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

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

А вот с Андроидом куча проблем

1. Не смог запустить программу на Андроид 6.1. У меня реализован SplashScreen, так вот при показе главной формы получаю 

Cannot create OpenGL context for 'eglMakeCurrent'

откуда ноги растут пока не понятно. На Андроид 8.0 все запустилось нормально. Пробывал понижать версию SDK - не помогло, есть подозрение, что глючит какой-то из визуальных компонентов, дебаг не помог, весь код по onshow главной формы отрабатывает, а затем делфа начинает показывать окно CPU и в какой-то момент выскакивает ошибка.

2. На Андроид 8 не работает SplashScreen - то есть вообще. Показывает заставку и затем сразу главное окно, пока не ясно что это.

3. Не работают ПУШи - не формируется Токен, вообще не стартует сервис пушей, говорит, чего-тоне хватает, буду разбираться. 

4. Есть у меня прозрачная форма, на которой лежит прямоугольник с прозрачностью (Opacity). Так вот он показывается просто черным, прозрачность не отрабатывает, хотя на непрозрачной форме работает корректно. В параметрах Brush прямоугольника не отображаются правильно значения цвета.

Изменено пользователем gonzales
Ссылка на комментарий
  • Ответы 67
  • Создана
  • Последний ответ

Лучшие авторы в вопросе

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

  • 0
В 12.03.2019 в 08:48, GASCHE сказал:

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

Прошу прощения за долгое отсутствие

Вот накидал простой исходникtest10.3.zip. В проекте 3 формы, первой создается SplashForm. Остальные формы имеют в OnCreate высоконагруженные вычисления, поэтому после каждого создания формы отображаю на SplashForm статус формы. Дабы все это отрисовывалось использую Application.processmessages.

 

Ссылка на комментарий
  • 0
В 14.03.2019 в 11:46, gonzales сказал:

Прошу прощения за долгое отсутствие

Вот накидал простой исходникtest10.3.zip. В проекте 3 формы, первой создается SplashForm. Остальные формы имеют в OnCreate высоконагруженные вычисления, поэтому после каждого создания формы отображаю на SplashForm статус формы. Дабы все это отрисовывалось использую Application.processmessages.

 

Application.ProcessMessages;
 Application.CreateForm(TForm1, Form1);
 Label2.text:='Form1 Created';
 Application.ProcessMessages;
 Application.CreateForm(TForm2, Form2);
 Label2.text:='Form2 Created';
 Application.ProcessMessages;
 Application.MainForm:=Form1;
 Form1.Show;
 SplashForm.Hide;
 SplashForm.Release;

Можно заменить на 

 tthread.CreateAnonymousThread(procedure
 begin
    sleep(1000);
    tthread.Synchronize(tthread.CurrentThread, procedure
   begin
      Application.CreateForm(TForm1, Form1);
   end);
    while not assigned(form1) do
     sleep(0);
   tthread.Synchronize(tthread.CurrentThread, procedure
   begin
    Label2.text:='Form1 Created';
   end);
   sleep(200);
   tthread.Synchronize(tthread.CurrentThread, procedure
   begin
    Application.CreateForm(TForm2, Form2);
   end);
   while not assigned(form2) do
     sleep(0);
   tthread.Synchronize(tthread.CurrentThread, procedure
   begin
     Label2.text:='Form2 Created';
     Application.MainForm:=Form1;
     Form1.Show;
     SplashForm.Hide;
     SplashForm.DisposeOf;
   end);
 end).Start;

но как было сказано выше, использование Sleep не лучший вариант.

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

сколько бед принесла уже стрельба в ногу под названием ProcessMessages

как хорошо, что в Андроиде наконец всех отучат от этого крайне вредного трюка

давайте формально 

все что там у вас "высоконагруженное" выносите в потоки и пусть они работают. Ваши "потоки" пасутся в главном (Synchronize) и никакого толка нет

концепцию надо поменять. запустили поток и занимайтесь своим делом. например покажите Splash

а вернется поток - вот по возвращению и сделаете то, что этот Splash закроет.

и уж точно потоки не должны ничего общего иметь с формами

я писал статью про потоки, там про сплеши тоже есть в блоге и про ProcessMessages отдельная боль...

http://www.cyberforum.ru/blogs/469693/blog4875.html

 

Ссылка на комментарий
  • 0
В 16.03.2019 в 20:06, IS1 сказал:

но как было сказано выше, использование Sleep не лучший вариант.

Ну да уж)))

14 часов назад, krapotkin сказал:

сколько бед принесла уже стрельба в ногу под названием ProcessMessages

как хорошо, что в Андроиде наконец всех отучат от этого крайне вредного трюка

Я читал этот Ваш пост и вот этот http://www.cyberforum.ru/blogs/469693/blog4909.html, натыкался на него еще до этого обсуждения. Тем не менее я считаю, что использование ProcessMessages в простых случаях оправдано. Ведь это ни что иное, как изменение приоритетов процессов, например когда нужно просто перерисовать форму, с помощью ProcessMessages останавливаем текущий процесс и запускаем процессы в очереди. Но это сугубо ИМХО. Зачем было убирать его мне не понятно, хочешь используй, не хочешь - не используй, делай костыли, как предложил IS1 со слипами, потоками и прочими радостями.

15 часов назад, krapotkin сказал:

все что там у вас "высоконагруженное" выносите в потоки и пусть они работают. Ваши "потоки" пасутся в главном (Synchronize) и никакого толка нет

концепцию надо поменять. запустили поток и занимайтесь своим делом. например покажите Splash

а вернется поток - вот по возвращению и сделаете то, что этот Splash закроет.

С потоками мне все понятно, сам их активно использую, например при раскодировании изображений с ip-камер. Но как их использовать, когда есть очередность действий в главном потоке?

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

Ссылка на комментарий
  • 0
18 часов назад, krapotkin сказал:

как хорошо, что в Андроиде наконец всех отучат от этого крайне вредного трюка

C этим согласен, но как бы было хорошо если бы андроид научили "тормозить" потоки типа WaitForSingleObject. 

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

научили конечно ))) все придумано до нас

вот статья

вот так в грубом приближении должно это быть 

p.s. Забыл удалить из ваших форм эти циклы, которых там быть не должно

Форма - это интерфейс взаимодействия с пользователем. Данные должны жить отдельно.

test10.3.zip

Изменено пользователем krapotkin
Ссылка на комментарий
  • 0
56 минут назад, krapotkin сказал:

вот так в грубом приближении должно это быть

Спасибо!

До меня начало доходить, нужно полностью отойти от метода программирования, когда в коде основной формы пишутся все процедуры и функции, все выносить в отдельные юниты, в которых в потоках (потоке) обрабатывается вся логика и лишь через синхронизацию выдает информацию в главный поток. А главный поток по сути свободен, занят лишь перерисовкой форм и получением событий мыши. 

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

Че то я опять запутался))) Допустим я создал свой класс типа Tthreat, в котором у меня крутится вся логика. В частности есть public свойства SettingsXML - XMLDocument и settingsfilename - поле для хранения пути к файлу настроек. Далее я создаю экземпляр этого класса, который находится на form1.

form1.SystemClient:= TSystemClient.Create;

При этом экземпляр же находится в главном потоке?

При вызове вот такого метода, в каком потоке он будет выполняться?

form1.SystemClient.SettingsXML.LoadFromFile(form1.SystemClient.settingsfilename);

 

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

И еще, если я в своем классе TThread создаю форму для отображение прогресс бара

 

application.CreateForm(TForm27, Form27);
  Form27.ProgressBar1.Max := highbyte + 1;
  Form27.ProgressBar1.value := 0;
  Form27.StartUpLabel.text := inttostr(filesize);

Должен я обращаться к ней через синхронизацию?

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

да.

хотя идея создавать форму из потока так себе идея.

я стараюсь просто потоку с собой сунуть ссылку на прогресс-бар, фрейм или форму. 

и уж точно не делать это глобальной переменной !

Ссылка на комментарий
  • 0
1 час назад, krapotkin сказал:

да.

хотя идея создавать форму из потока так себе идея.

я стараюсь просто потоку с собой сунуть ссылку на прогресс-бар, фрейм или форму. 

и уж точно не делать это глобальной переменной !

Спасибо!

Не могли бы Вы прокомментировать еще мой пост выше

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

я ответил) распространяю :

1. работа с формами из потока, в т.ч. создание - только через синхронизацию

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

3. КЛасс =class(TThread) это не поток. это просто класс, один из методов которого (Execute) при правильном запуске (Start) будет выполняться в другом потоке ОС. А можно просто взять и вызвать th.Execute. И этот метод выполнится в том потоке откуда и вызван. Так что это просто класс...

Ссылка на комментарий
  • 0
58 минут назад, krapotkin сказал:

3. КЛасс =class(TThread) это не поток. это просто класс, один из методов которого (Execute) при правильном запуске (Start) будет выполняться в другом потоке ОС. А можно просто взять и вызвать th.Execute. И этот метод выполнится в том потоке откуда и вызван. Так что это просто класс...

Тогда как посоветуете поступить.

Есть класс (условно TSystem), который содержит кучу свойств и методов для работы приложения (всю логику). Там и все структуры, и работа с XML, и работа с TCP-клиентом. Задача: развязать работу экземпляра этого класса с формой. Как Вы и советовали, логика отдельно, интерфейс отдельно. Я (по наивности наверное) думал, что если этот класс будет типа TThreat, то он автоматом будет работать в новом потоке, но судя по Вашим комментариям - это не так. В методе TSystem.Execute у меня пока зашит пока только прием данных от TCP-клиента. Как правильно организовать работу, чтобы все методы класса TSystem выполнялись в отдельном потоке, и при этом я мог их запускать из основного потока. Например есть метод TSystem.SendMessage, если я обращаюсь к нему с главной формы, в каком потоке он будет выполнен?

 

Извините, что (скорее всего) задаю тупые вопросы, но обратиться больше не к кому))). Заранее спасибо за любые ответы.

 

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

не нужно делать долгоиграющие потоки

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

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

нет никакого смысла все время крутить потоки.

Ссылка на комментарий
  • 0
6 часов назад, gonzales сказал:

И еще, если я в своем классе TThread создаю форму для отображение прогресс бара

Пожалейте пользователя, перед глазами две формы плюс splash форма да еще форма с  прогресс баром при этом на каждой что-то меняется куда ему смотреть и на какой жать клавиши ☺️

Ссылка на комментарий
  • 0
В 22.03.2019 в 16:32, krapotkin сказал:

не нужно делать долгоиграющие потоки

На форуме обсуждал в соседней ветке.

Я хочу открыть соединение с сервером и получать в него данные, пока живо приложение. Соответственно, было бы здорово, если бы все эти манипуляции происходили бы в потоке, отдельно от форм. Поэтому рассматриваю вариант, когда поток стартует вместе с приложением, и живет все время. Ну и заодно хочу забросить в него все остальное. А почему не следует так делать?

Ссылка на комментарий
  • 0
В 22.03.2019 в 12:03, gonzales сказал:

И еще, если я в своем классе TThread создаю форму для отображение прогресс бара

Если 

 

13 часов назад, gonzales сказал:

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

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

Ссылка на комментарий
  • 0
1 час назад, GASCHE сказал:

Если

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

1 час назад, GASCHE сказал:

Основной поток простаивает зачем нужен дополнительный?

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

 

В 22.03.2019 в 18:37, GASCHE сказал:

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

У вас очень странное представление о UI. Вы правда считаете, что я демонстрирую пользователю одновременно Сплэш, две формы, и повергающий его в экстаз прогрессбар??

Ссылка на комментарий
  • 0
В 19.03.2019 в 12:41, krapotkin сказал:

вот так в грубом приближении должно это быть 

p.s. Забыл удалить из ваших форм эти циклы, которых там быть не должно

продолжаю разбираться. вернулся обратно к коду, предложенному уважаемым krapotkin

Хочу внести одно изменение, чтобы форма1 создавалась в процедуре TMyDatamodel.ObtainData

procedure TMyDatamodel.ObtainData;
var
  tasks: array of ITask;
  task: ITask;
  f: TForm1;

  procedure CreateTasks;
  begin
  tasks :=
    [
    TTask.Create(procedure ()
    begin
      sleep(2000);
      data1:='data1';
    end),
    TTask.Create(procedure ()
    begin
      sleep(2000);
      data2:='data2';
      f:=TForm1.Create(NIL);
      form1.Show;
    end)
    ];
  end;
begin
  CreateTasks;
  for task in tasks do
    task.start;
  TTask.WaitForAll(tasks);
end;

В одну из задач воткнул создание формы, при этом приложение отрабатывает не корректно. Получаю AccessViolation на этапе form1.show. Подозреваю, что проблема в том, что форма создана в потоке. Перебросил form1.show в SplashForm.FormCreate, ошибок нет, но и форма не показывается. 

procedure TSplashForm.FormCreate(Sender: TObject);
begin
  AniIndicator1.Enabled := True;
  AniIndicator1.Visible := True;
  b1.Visible := false;
  TTask.Run(
    procedure
    begin
      datamodel.ObtainData;
      TThread.Synchronize(nil,
        procedure
        begin
          AniIndicator1.Enabled := false;
          AniIndicator1.Visible := false;
          b1.Visible := True;
          lbl1.Text := datamodel.data1;
          lbl2.Text := datamodel.data2;
          form1.Show;
        end);

    end);
end;

Что я делаю не так??)))

Ссылка на комментарий
  • 0
f:=TForm1.Create(NIL);
      form1.Show;

вы создали объект и ссылку на него положили в переменную F

а теперь объекту из другой переменной form1 пытаетесь вызвать метод Show

переменная form1 пустая поэтому AV

и все равно из потока работать с формами нельзя

TTask.Create(procedure ()
    begin
      sleep(2000);
      data2:='data2';
      tthread.synchronize(nil, procedure begin
      f:=TForm1.Create(NIL);
      f.Show;
      end)
    end)

 

Ссылка на комментарий
  • 0
15 минут назад, krapotkin сказал:

вы создали объект и ссылку на него положили в переменную F

а теперь объекту из другой переменной form1 пытаетесь вызвать метод Show

аа, точно, спасибо. чего-то затупил.

Правильно вот так

procedure TSplashForm.FormCreate(Sender: TObject);
var
  f: TForm1;
begin
  AniIndicator1.Enabled := True;
  AniIndicator1.Visible := True;
  b1.Visible := false;
  TTask.Run(
    procedure
    begin
      datamodel.ObtainData;
      TThread.Synchronize(nil,
        procedure
        begin
          AniIndicator1.Enabled := false;
          AniIndicator1.Visible := false;
          b1.Visible := True;
          lbl1.Text := datamodel.data1;
          lbl2.Text := datamodel.data2;
          f := TForm1.Create(NIL);
          f.Show;
        end)
    end);
end;

 

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

Что-то все равно у меня ничего путного не получается. 

Я создал класс, типа TThread

type
  TClient = class(TThread)
  public
....

На загрузочной форме создаю экземпляр этого класса

procedure TSplashForm.LoadProgramm;
begin
  StartUpLabel.Text := 'Инициализация';
  Application.CreateForm(TForm1, Form1);
  Client:= TClient.Create;
  label1.Text:=VERSION;
end;

Соответственно в конструкторе класса провожу загрузку приложения и через синхронизацию обновляю надпись на загрузочной форме

  ...
TThread.Synchronize(TThread.CurrentThread,
    procedure
    begin
      SplashForm.StartUpLabel.text := 'права пользователя';
    end);
...

 но обновления надписей не вижу.

 

Вопросов возникает несколько

1. TClient при такой конструкции работает в отдельном потоке

2. Правильно ли я провожу синхронизацию с главным потоком?

3. Свободен ли в этот момент главный поток?

 

 

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

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

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

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

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

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

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

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

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

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

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

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