Recent

Author Topic: Can I use TThread in android app in the same way like for windows app?  (Read 10330 times)

Atak_Snajpera

  • New Member
  • *
  • Posts: 31
I have added cthreads to lpr file then I try creating and running thread the same how I do on windows.

Simple example:

Code: Pascal  [Select][+][-]
  1. type
  2.   TWorkerThread = class(TThread)
  3.   private
  4.     { Private declarations }
  5.     x:integer;
  6.     procedure UpdateValue;
  7.   protected
  8.     procedure Execute; override;
  9.   end;    

Code: Pascal  [Select][+][-]
  1. procedure TForm1.ButtonClick(Sender: TObject);
  2. begin
  3.  
  4.      WorkerThread:=TWorkerThread.Create(true);
  5.      WorkerThread.FreeOnTerminate:=false;
  6.      WorkerThread.Priority:=tpNormal;
  7.      WorkerThread.Start;
  8.  
  9. end;        

Code: Pascal  [Select][+][-]
  1. procedure TWorkerThread.Execute;
  2. begin
  3.    x:=0;  
  4.  
  5.    repeat
  6.          Inc(x);
  7.          Synchronize(UpdateValue);
  8.          sleep(1000);
  9.    until Terminated=true;
  10.  
  11. end;  

Code: Pascal  [Select][+][-]
  1. procedure TWorkerThread.UpdateValue;
  2. begin
  3.    form1.jTextView.text:=IntToStr(x);
  4.  
  5. end;

When I press button in android emulator nothing happens!
« Last Edit: November 25, 2021, 06:35:09 pm by Atak_Snajpera »

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Can I use TThread in android app in the same way like for windows app?
« Reply #1 on: November 26, 2021, 05:32:11 am »
TThread works on Android.

Synchronize needs CheckSynchronize to be called inside the main loop of the app. This is by default on Windows for GUI applications. Not on terminal or Android apps. You can add it there.

Test TThread without Synchronize.

Atak_Snajpera

  • New Member
  • *
  • Posts: 31
Re: Can I use TThread in android app in the same way like for windows app?
« Reply #2 on: November 26, 2021, 08:06:18 pm »
Where should I put CheckSynchronize exactly?

MarkMLl

  • Hero Member
  • *****
  • Posts: 7884
Re: Can I use TThread in android app in the same way like for windows app?
« Reply #3 on: November 26, 2021, 08:20:14 pm »
Seconded. @engkin, could we have a concise example please?

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Can I use TThread in android app in the same way like for windows app?
« Reply #4 on: November 27, 2021, 01:27:15 am »
I'll provide an example as soon as get a chance.

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Can I use TThread in android app in the same way like for windows app?
« Reply #5 on: November 27, 2021, 09:45:34 am »
While other possibilities are there, I'll assume LAMW is being used here since the original post mentioned jTextView. If you followed my first reply, you'll see the thread is working but can not call Synchronize.

To prove that Synchronize works, simply add a jTimer to your main form and have it call CheckSynchronize(). If you are satisfied with this timer, good for you.

A call to Synchronize uses WakeMainThread. Which makes finding a way to call CheckSynchronize on the main thread simple. Android provides RunOnUiThread. Unfortunately the implementation in LAMW is not correct. It uses PJNIEnv of the main thread instead of the calling thread. A thread var can be filled by each thread. Along these lines:
Code: Pascal  [Select][+][-]
  1. threadvar
  2.   env:PJNIEnv;//<--- has to be a threadvar
  3.  
  4. procedure TWorkerThread.Execute;
  5. begin
  6.   gVM^.AttachCurrentThread(gVM,@env,nil);//<--- needed for every thread
  7.   WakeMainThread:=LetsWakeMainThread;//<--- needed once
  8.   x:=0;
  9.   repeat
  10.     inc(x);
  11.     Synchronize(UpdateValue);
  12.     Sleep(1000);
  13.   until Terminated;
  14.   gVM^.DetachCurrentThread(gVM);//<--- when you are done with the thread (Free/Destroy)
  15. end;

LetsWakeMainThread is:
Code: Pascal  [Select][+][-]
  1. procedure TWorkerThread.LetsWakeMainThread(Sender:TObject);
  2. begin
  3.   //MainForm.RunOnUiThread(Integer(Self));//<--- Wrong env variable, not for this thread
  4.   TAndroidModule1(MainForm).RunOnUiThread_corrected(env,0);
  5. end;

RunOnUiThread_corrected  is:
Code: Pascal  [Select][+][-]
  1. procedure TAndroidModule1.RunOnUiThread_corrected(correct_env:PJNIEnv;_tag: integer);
  2. begin
  3.   //in designing component state: set value here...
  4.   if Initialized then
  5.      jni_proc_i(correct_env, jSelf, 'RunOnUiThread', _tag);
  6. end;

And the most important part is to add CheckSynchronize() to the OnRunOnUiThread event of the main form:
Code: Pascal  [Select][+][-]
  1. procedure TAndroidModule1.AndroidModule1RunOnUiThread(Sender:TObject;tag:integer);
  2. begin
  3.   CheckSynchronize();
  4. end;


Full code of the thread:
Code: Pascal  [Select][+][-]
  1. unit uThreadTest;
  2.  
  3. {$mode delphi}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils,
  9.   AndroidWidget,And_jni;
  10.  
  11. type
  12.  
  13.   { TWorkerThread }
  14.  
  15.   TWorkerThread=class(TThread)
  16.   private
  17.     procedure UpdateValue;
  18.   protected
  19.     procedure Execute; override;
  20.   public
  21.     MainForm:jForm;
  22.     x:integer;
  23.     OnUpdate:Procedure of object;
  24.  
  25.     procedure LetsWakeMainThread(Sender: TObject);
  26.   end;
  27.  
  28. implementation
  29. uses
  30.   unit1;
  31.  
  32. { TWorkerThread }
  33.  
  34. procedure TWorkerThread.UpdateValue;
  35. begin
  36.   if Assigned(OnUpdate) then
  37.     OnUpdate;
  38. end;
  39.  
  40. threadvar
  41.   env:PJNIEnv;//<--- has to be a threadvar
  42.  
  43. procedure TWorkerThread.Execute;
  44. begin
  45.   gVM^.AttachCurrentThread(gVM,@env,nil);//<--- needed for every thread
  46.   WakeMainThread:=LetsWakeMainThread;//<--- needed once
  47.   x:=0;
  48.   repeat
  49.     inc(x);
  50.     Synchronize(UpdateValue);
  51.     Sleep(1000);
  52.   until Terminated;
  53.   gVM^.DetachCurrentThread(gVM);//<--- when you are done with the thread (Free/Destroy)
  54. end;
  55.  
  56. procedure TWorkerThread.LetsWakeMainThread(Sender:TObject);
  57. begin
  58.   //MainForm.RunOnUiThread(Integer(Self));//<--- Wrong env variable, not for this thread
  59.   TAndroidModule1(MainForm).RunOnUiThread_corrected(env,0);
  60. end;
  61.  
  62. end.

Main form relevant code:
Code: Pascal  [Select][+][-]
  1. procedure TAndroidModule1.LetsUpdate;
  2. begin
  3.   jTextView1.Text:=WorkerThread.x.ToString;
  4. end;
  5.  
  6. procedure TAndroidModule1.RunOnUiThread_corrected(correct_env:PJNIEnv;_tag: integer);
  7. begin
  8.   if Initialized then
  9.      jni_proc_i(correct_env, jSelf, 'RunOnUiThread', _tag);
  10. end;
  11.  
  12. procedure TAndroidModule1.StartBtnClick(Sender:TObject);
  13. begin
  14.   if WorkerThread=nil then
  15.   begin
  16.     WorkerThread:=TWorkerThread.Create(True);
  17.     WorkerThread.MainForm:=Self;
  18.     WorkerThread.OnUpdate:=LetsUpdate;
  19.     WorkerThread.Start;
  20.   end;
  21. end;
  22.  
  23. procedure TAndroidModule1.StopBtnClick(Sender:TObject);
  24. begin
  25.   WorkerThread.Terminate;
  26. end;
  27.  

MarkMLl

  • Hero Member
  • *****
  • Posts: 7884
Re: Can I use TThread in android app in the same way like for windows app?
« Reply #6 on: November 27, 2021, 10:04:46 am »
Thanks very much for that, it gives me a good incentive to look at LAMW and possibly to investigate threads on Termux.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

jmpessoa

  • Hero Member
  • *****
  • Posts: 2312
Re: Can I use TThread in android app in the same way like for windows app?
« Reply #7 on: November 27, 2021, 04:14:33 pm »
@engkin

Nice!

Can you, please, put your LAMW project in some "open drive"  (or here, if possible)


So we can add it to LAMW "demos"!

Thank you!
Lamw: Lazarus Android Module Wizard
https://github.com/jmpessoa/lazandroidmodulewizard

engkin

  • Hero Member
  • *****
  • Posts: 3112
Re: Can I use TThread in android app in the same way like for windows app?
« Reply #8 on: November 27, 2021, 09:36:58 pm »
Can you, please, put your LAMW project in some "open drive"  (or here, if possible)

Done!

jmpessoa

  • Hero Member
  • *****
  • Posts: 2312
Re: Can I use TThread in android app in the same way like for windows app?
« Reply #9 on: November 28, 2021, 06:55:01 am »

Done!

Thank you!
Lamw: Lazarus Android Module Wizard
https://github.com/jmpessoa/lazandroidmodulewizard

Atak_Snajpera

  • New Member
  • *
  • Posts: 31
Re: Can I use TThread in android app in the same way like for windows app?
« Reply #10 on: September 02, 2022, 01:06:58 am »
"Unfortunately the implementation in LAMW is not correct. It uses PJNIEnv of the main thread instead of the calling thread. "

Has this been already fixed in latest version of lamw?

 

TinyPortal © 2005-2018