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

Обращение к серверу в потоке (Android)

Вопрос

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

Решаю следующую задачу, в приложении динамически формируются разные объекты, наследники от одного класса. При формировании объектов заполняется динамический массив этих элементов. Далее я хочу в отдельном потоке для каждого из элементов массива получить его состояние, то есть делаю запрос к серверу. Все это повешено на таймер, каждую секунду должен отрабатываться запрос. Все более менее работает в Windows, а на Андроиде со временем приложение валится. Вот код таймера, для читаемости я удалил куски с различными вариантами E. RootElements - это массив TEssense от которого есть наследники. Функции GetBoardCurrentValue, GetBoardMaxValue - по сути запросы к серверу. 

Подскажите, правильно ли я оформляю работу с потоками для работы на Андроиде?

procedure TForm1.MasterTimerTimer(Sender: TObject);
begin
  TTask.Run(
    procedure
    var
      l, d, a: byte;
      i,j:integer;
      E: TEssence;
      p: Pointer;
      VirtualNode: IXMLNode;
      VirtualElementNode: IXMLNode;
      id: byte;
    begin
      l := Length(Form1.RoomElements);
      for j := 0 to l - 1 do
      begin
        E := Form1.RoomElements[j];

        // Реле
        if E is TRele then
        begin
          d := (E as TRele).Device_ID;
          a := (E as TRele).Device_Adress;
          if Form1.GetBoardCurrentValue(d, a) = true then
          begin
            TThread.Synchronize(nil,
              procedure
              begin
                (E as TRele).ReleSwitch.IsChecked := Form1.device[d].Board[a].CurrentValue.ToBoolean;
              end);
          end;
          // (E as TRele).ReleOnTimer(E)
        end

        // Диммер
        else if E is TDimmer then
        begin
          d := (E as TDimmer).Device_ID;
          a := (E as TDimmer).Device_Adress;
          if Form1.GetBoardMaxValue(d, a) = true then
          begin
            TThread.Synchronize(nil,
              procedure
              begin
                if (Form1.device[d].Board[a].Type_ID = TType.Светодиод) or
                  (Form1.device[d].Board[a].Type_ID = TType.Диммер220) then
                begin
                  (E as TDimmer).DimmerValue.Text := (Form1.device[d].Board[a].MaxValue).ToString;
                end;
              end);
          end;
          // (E as TDimmer).DimmerOnTimer(E)
        end

        // Таймер
        else if E is TSTimer then
        begin
          id := (E as TSTimer).STimerIndex;
          Form1.FillHTTPRequest(0, 0, HTTP_GET_TIMER_INFO, id);
          if Form1.AnswerIsComming = HTTP_GET_TIMER_INFO then
          begin
            TThread.Synchronize(nil,
              procedure
              begin
                if Form1.HTTPAnswer.Data1 = 0 then
                  (E as TSTimer).Interval.Text := 'OFF'
                else
                  (E as TSTimer).Interval.Text := 'ON'
              end);
          end;
          // (E as TSTimer).STimerOnTimer(E);
        end;
      end;
    end);
end;

  

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


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

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

  • 0

Да, забыл отметить, что без использования потока все работает стабильно, но соответственно есть заметные подлагивания. 

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


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

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

Вот она

procedure TForm1.SendHTTPMessage;
    var
      t_out, t_in: TIdBytes;
      Size: TSizeF;
      localAnswer: byte;
      localicon: byte;
      localserver: boolean;
    begin
      try
        Size.cx := 16;
        Size.cy := 16;
        if Client1.Connected = false then
          Client1.Connect;

        if Client1.Connected = true then
        begin
          localicon := 15;
          localserver := true;
          localAnswer := 0;
          SetLength(t_out, SizeOf(HTTPRequest));
          Move(HTTPRequest, t_out[0], SizeOf(HTTPRequest));
          Client1.Socket.WriteBufferOpen;
          Client1.Socket.Write(t_out, 13);
          Client1.Socket.WriteBufferFlush;
          Client1.Socket.WriteBufferClose;
          SetLength(t_in, SizeOf(THTTPAnswer));

          try
            Client1.Socket.ReadBytes(t_in, SizeOf(THTTPAnswer), false);
            Move(t_in[0], HTTPAnswer, Length(t_in));
            localAnswer := HTTPAnswer.Command;
            Client1.Disconnect;
          except
            localicon := 7;
            localserver := false;
            localAnswer := 0;
            Form1.Client1.Disconnect;
          end;
        end
        else
        begin
          Client1.Disconnect;
          localicon := 7;
          localserver := false;
          localAnswer := 0;
        end;
      except
        on E: Exception do
        begin
          // showmessage('Error: ' + E.Message);
          Client1.Disconnect;
          localicon := 7;
          localserver := false;
          localAnswer := 0;
        end;
      end;

          Form1.ConnectImage.Bitmap := Form1.IconList.Bitmap(Size, localicon);
          AnswerIsComming := localAnswer;
          Form1.ServerOK := localserver;


end;

 

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


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

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

Опишу более подробно.

Есть объекты, у них есть состояние, о нем знает сервер. Соответственно клиентов может быть несколько и у всех должно синхронно обновляться состояние при изменении его на сервере. Сервер - это МК со своими прибамбасами, но сейчас не об этом. Клиенты - приложение для IOS и Android. Задача - получать данные с сервера о состоянии активных в данный момент объектах, желательно, чтобы основной интерфейс не тормозил в моменты получения информации.

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


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

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

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


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

На первый взгляд можно заметить следующее:

1. Обращение к форме из потока без синхронизации

l := Length(Form1.RoomElements);
E := Form1.RoomElements[j];

Так делать нельзя. SendHTTPMessage - тоже самое.

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

3. У вас сколько объектов по которому цикл проходит каждую секунду? И для каждого объекта вызывается Get запрос на веб сервер? Бедный сервер. Данные нужно получать сразу для всех объектов, и уже в клиенте разбирать, что вам нужно, а что нет. А иначе ваши клиенты положат вам ваш же сервер рано или поздно.

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

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


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

Спасибо Maximus, учту. 

Несколько уточняющих вопросов

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

2. С таймером - хорошая мысль, попробую, вдруг действительно не успевает отработать, это объяснило бы глюки на андроиде.

3. Объектов до 10 и по каждому запрос, только запрос не HTTP, так как у меня не web-сервер, а это просто пакет байт, на который сервер отвечает таким же пакетом. Я уже думаю над тем, чтобы передавать всю информацию в одном пакете, но для этого придется полностью переколбасить сервер, а сейчас пока на это нет времени. А нельзя TCPClient заставить работать в асинхронном режиме? 

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


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

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

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

Но вот это же точно визуальный элемент?

Form1.ConnectImage.Bitmap := Form1.IconList.Bitmap(Size, localicon);

 

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

3. Объектов до 10 и по каждому запрос, только запрос не HTTP, так как у меня не web-сервер, а это просто пакет байт, на который сервер отвечает таким же пакетом. Я уже думаю над тем, чтобы передавать всю информацию в одном пакете, но для этого придется полностью переколбасить сервер, а сейчас пока на это нет времени. А нельзя TCPClient заставить работать в асинхронном режиме? 

Тогда это уже менее страшно, я почему-то подумал, что обращение идёт через HTTP. TCPClient не имеет такой возможности, только самостоятельно потоки делать.

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


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

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

либо в обработчике окончания потока, либо через синхронизацию не заканчивая поток

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


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

Но вот это же точно визуальный элемент?

Разумеется. Я не подумал, что вызывая SendHTTPMessage в потоке я также должен синхронизировать результаты. Пока не удается завернуть SendHTTPMessage в поток, обмен данными не идет. Буду искать ошибки. Во всяком случае большое спасибо за наводки

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


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

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

либо в обработчике окончания потока, либо через синхронизацию не заканчивая поток

Для асинхронного режима в Windows  есть WaitForSingleObject( Event, INFINITE ) , что аналогичное можно использовать в много платформенных приложениях?

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


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

У меня все сделано на MQTT. МК arduino uno на данный момент вещает на три androida и две винды. Все четко и синхронно.

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


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

У меня все сделано на MQTT. МК arduino uno на данный момент вещает на три androida и две винды. Все четко и синхронно.

Это прекрасно)))

А как реализован MQTT в firemonkey? А брокером сама ардуино является?

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


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

Есть у tms компонент, с ним все работает нормально, но он платный. Я использовал вот эту библиотеку https://github.com/join2017/dmqtt . Брокер на данный момент вот этот использую https://cloudmqtt.com/ . Arduino туда шлет и от туда принимает. Но сейчас свой сервак поднимаю.

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


Ссылка на сообщение
Поделиться на другие сайты
  • 0
В 19.10.2017 в 14:35, GASCHE сказал:

WaitForSingleObject

это как бы стоять и ждать пока
можно с тем же успехом 
repeat ... until Done;
поток блокируется.

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


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

это как бы стоять и ждать пока
можно с тем же успехом 
repeat ... until Done;
поток блокируется.

Несколько не так, WaitForSingleObject поток засыпает и ждет тот же Event что хорошо для реализации асинхронного режима, repeat ... until Done поток не спит, нагружая процессор не нужной работой.

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


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

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

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


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

Для асинхронного режима в Windows  есть WaitForSingleObject( Event, INFINITE )

Не очень понял, чем это может помочь! В общем процедуру, которая в потоке запрашивает у сервера информацию и обновляет состояние компонента я написал, но теперь есть другая засада. Эта процедура срабатывает по таймеру в 1 сек, соответственно работает в своем потоке. Но иногда проявляется следующий баг, пользователь принудительно меняет состояние объекта (при этом он перерисовывается), и тут же перерисовывается обратно по таймеру (так как информация о смене состояния на сервер еще не попала) и только на следующем такте (обращении по таймеру к серверу) объект перерисуется в правильное состояние. Вопрос, могу ли я каким-то образом в момент нажатия пользователем на объект остановить выполнение задачи в потоке?

Надеюсь что-то понятно из моего объяснения))

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


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

Не очень понял, чем это может помочь!

В windows это позволяет запустить поток когда вам нужно, а не по таймеру.

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

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


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

Не очень понял, чем это может помочь! В общем процедуру, которая в потоке запрашивает у сервера информацию и обновляет состояние компонента я написал, но теперь есть другая засада. Эта процедура срабатывает по таймеру в 1 сек, соответственно работает в своем потоке. Но иногда проявляется следующий баг, пользователь принудительно меняет состояние объекта (при этом он перерисовывается), и тут же перерисовывается обратно по таймеру (так как информация о смене состояния на сервер еще не попала) и только на следующем такте (обращении по таймеру к серверу) объект перерисуется в правильное состояние. Вопрос, могу ли я каким-то образом в момент нажатия пользователем на объект остановить выполнение задачи в потоке?

Прям немедленно остановить нельзя, но можно вызвать метод Cancel

var
	Task   : ITask;
...
Task := TTask.Run(...);
...
Task.Cancel; //когда нужно остановить

А внутри таска сделать проверки, что если выполняется

Task.Status = TTaskStatus.Canceled

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

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


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

Прям немедленно остановить нельзя, но можно вызвать метод Cancel

Спасибо большое, как раз то что нужно!!! Реализовал, все работает

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


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

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

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

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

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

  Разрешено использовать не более 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 пользователей онлайн

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

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