Lazarus

Programming => Operating Systems => Android => Topic started by: Robert Gilland on June 14, 2019, 04:27:36 am

Title: LAMW and TThread
Post by: Robert Gilland on June 14, 2019, 04:27:36 am
The below code crashes my app, id dies when it calls the line "inherited Create(TRUE)", any Ideas?

Code: Pascal  [Select][+][-]
  1. type
  2.   TTestThread = class(TThread)
  3.      procedure Execute;  override;
  4.      constructor Create;
  5.    end;
  6.  
  7.  constructor TTestThread.Create;
  8. begin
  9.   inherited Create(TRUE);
  10.   FreeOnTerminate := TRUE;
  11. end;
  12.  
  13. procedure TTestThread.Execute;
  14. begin
  15.  
  16. end;
  17.  
  18. procedure TAndroidModule2.TestThreading;
  19. begin
  20.   TTestThread.Create;
  21. end;
  22.  
Title: Re: LAMW and TThread
Post by: SymbolicFrank on June 14, 2019, 08:07:30 am
Do you call the Create of the instance, instead of the type?
Title: Re: LAMW and TThread
Post by: PascalDragon on June 14, 2019, 09:06:14 am
Does your main project file have the cthreads unit in its usage clause? This unit is required on *nix systems which Android is one of. The Lazarus templates usually have the unit protected by a {$ifdef unix}{$ifdef usecthreads}cthreads{$endif}{$endif} or so, so you need to define the usecthreads define in that case (or remove the ifdef altogether).
Title: Re: LAMW and TThread
Post by: Robert Gilland on June 16, 2019, 01:50:54 am
Thank you PascalDragon, "cThreads" did stop the app crash.

However now I can't get the OnTerminate event to be called see below code.

When run the jProgressDialog does not close.

Any Ideas?

Code: Pascal  [Select][+][-]
  1. type
  2.   TTestThread = class(TThread)
  3.      procedure Execute;  override;
  4.      constructor Create( pOnTerminateEvent : TNotifyEvent);
  5.    end;
  6.    
  7.   TAndroidModule1 = class(jForm)  
  8.      dlgTestProgress: jDialogProgress;  
  9.      thrdSendOffLine : TTestThread;      
  10.   end;  
  11.    
  12.  
  13. procedure TAndroidModule1.TestTerminated(Sender: TObject);
  14. begin
  15.   dlgTestProgress.Close;
  16. end;
  17.  
  18. constructor TTestThread.Create( pOnTerminateEvent : TNotifyEvent);
  19. begin
  20.  inherited Create(TRUE);
  21.  OnTerminate := pOnTerminateEvent;
  22.  FreeOnTerminate := TRUE;
  23. end;
  24.  
  25.  
  26. procedure TTestThread.Execute;
  27. begin
  28.  
  29. end;
  30.  
  31. procedure TAndroidModule1.RunThreadTest;
  32. begin
  33.   dlgTestProgress.Show();
  34.   thrdSendOffLine  := TTestThread.Create(TestTerminated);
  35.   thrdSendOffLine.Start;
  36. end;  
  37.  
  38.  
Title: Re: LAMW and TThread
Post by: PascalDragon on June 22, 2019, 05:53:14 pm
It could be that the main thread is not calling CheckSynchronize as OnTerminate is called using Synchronize. I don't have enough experience with Android modules in FPC, so I don't know whether there is supposed to be component that's indeed calling that function or not.
Title: Re: LAMW and TThread
Post by: engkin on June 22, 2019, 07:24:21 pm
IIRC, your code in LAMW resides in a library (.so). Probably the best option for you to get TThread to work as you expect is to fake a main thread like in this case (https://forum.lazarus.freepascal.org/index.php?topic=44522.0).
Title: Re: LAMW and TThread
Post by: Robert Gilland on June 24, 2019, 05:38:47 am
I have looked at https://forum.lazarus.freepascal.org/index.php/topic,44522.0.html.

This looks rather not usable inside the LAMW framework, unless I am mistaken.
LAMW creates a libcontrols.so library, then does a lot of packaging to make an Androd App.

I will keep looking though

Title: Re: LAMW and TThread
Post by: jmpessoa on June 24, 2019, 06:13:09 am

Quote
This looks rather not usable inside the LAMW framework, unless I am mistaken....

I think you could give it a try ... LAMW lib/.so  is a "TCustomApplication",  too...

What is going to be precessed in the TThread?
Title: Re: LAMW and TThread
Post by: Robert Gilland on June 24, 2019, 06:49:13 am
The application simply makes web service calls in response to the users interactions, some of these web service calls may take some time. I want a thread to process the web service call. allowing the main app to show a progress dialog until the web service API returns. This is proving far more difficult than I hoped for. I still have not worked out how the packaging of the app works, so I don't know how to add a separate library beside as this solution states can be done.
Title: Re: LAMW and TThread
Post by: Robert Gilland on June 24, 2019, 06:54:32 am
I am wondering if there could not be a "jThread" component to make threads inside LAMW applications?
Title: Re: LAMW and TThread
Post by: jmpessoa on June 24, 2019, 06:58:06 am
Quote
so I don't know how to add a separate library beside as this solution states can be done....

Put your custom ".so"  [can be a simple raw ".so" ] in the same folder as  "libcontrols.so" .... 
LAMW will takes care of your library automatically...


Quote
I am wondering if there could not be a "jThread" component to make threads inside LAMW applications?

jHttpClient component has some "async" methods.....  what you need?
Title: Re: LAMW and TThread
Post by: Robert Gilland on June 24, 2019, 07:13:12 am
will give AppAsyncTaskDemo1 a try it does look promising
Title: Re: LAMW and TThread
Post by: Robert Gilland on June 24, 2019, 07:56:08 am
If I could make a "WST" ( web services toolkit ) transport based on jHttpClient async methods , then we just might have a viable solution.
Title: Re: LAMW and TThread
Post by: Robert Gilland on June 24, 2019, 08:59:49 am
We have a winner "jAsyncTask"can handle the requirement
Title: Re: LAMW and TThread
Post by: jmpessoa on June 24, 2019, 07:40:48 pm
Quote
We have a winner "jAsyncTask"can handle the requirement

Nice!

What about a simple demo  jAsyncTask +  WST?

You can help all LAMW/Lazarus/FreePascal  community!!!
Title: Re: LAMW and TThread
Post by: Robert Gilland on June 25, 2019, 08:53:11 am
here is the core code:

Code: Pascal  [Select][+][-]
  1. {Hint: save all files to location: C:\adt32\eclipse\workspace\asyncdemo\jni }
  2. unit unit1;
  3.  
  4. {$mode delphi}
  5.  
  6. interface
  7.  
  8. uses
  9.   Classes, SysUtils, Laz_And_Controls, AndroidWidget, user_service_intf,
  10.   user_service_intf_proxy, And_Log_h;
  11.  
  12. type
  13.  
  14.   { TAndroidModule1 }
  15.  
  16.   TAndroidModule1 = class(jForm)
  17.       jAsyncTask1: jAsyncTask;
  18.       jButton1: jButton;
  19.       jDialogProgress1: jDialogProgress;
  20.       jEditText1: jEditText;
  21.       jListView1: jListView;
  22.       procedure AndroidModule1Create(Sender: TObject);
  23.       procedure AndroidModule1Destroy(Sender: TObject);
  24.       procedure jAsyncTask1DoInBackground(Sender: TObject; progress: Integer;
  25.         out keepInBackground: boolean);
  26.       procedure jAsyncTask1PostExecute(Sender: TObject; progress: integer);
  27.       procedure jAsyncTask1PreExecute(Sender: TObject; out
  28.         startProgress: integer);
  29.       procedure jButton1Click(Sender: TObject);
  30.     private
  31.       {private declarations}
  32.       procedure LogMessage( psMsg : String );
  33.       procedure   RunGetUsers;
  34.       function CreateUserProxy : UserService;
  35.     public
  36.       {public declarations}
  37.       slUsers : TStringList;
  38.   end;
  39.  
  40. var
  41.   AndroidModule1: TAndroidModule1;
  42.  
  43. implementation
  44.  
  45. {$R *.lfm}
  46.  
  47. uses soap_formatter, json_formatter, xmlrpc_formatter, fpc_http_protocol, service_intf;
  48.  
  49. { TAndroidModule1 }
  50.  
  51.  
  52. procedure TAndroidModule1.jAsyncTask1DoInBackground(Sender: TObject; progress: Integer; out keepInBackground: boolean);
  53. begin
  54.   RunGetUsers;
  55.   keepInBackground:= False;
  56. end;
  57.  
  58. procedure TAndroidModule1.AndroidModule1Create(Sender: TObject);
  59. begin
  60.   slUsers := tStringList.Create;
  61. end;
  62.  
  63. procedure TAndroidModule1.AndroidModule1Destroy(Sender: TObject);
  64. begin
  65.   slUsers.Free;
  66. end;
  67.  
  68. procedure TAndroidModule1.jAsyncTask1PostExecute(Sender: TObject; progress: integer);
  69. begin
  70.   LogMessage('Dialog Stop');
  71.   jDialogProgress1.Stop;
  72.   LogMessage('Async Stop');
  73.   jAsyncTask1.Done;
  74.   LogMessage('List View Assign');
  75.   jListView1.Items.Assign(slUsers);
  76.   ShowMessage(slUsers.text);
  77. end;
  78.  
  79. procedure TAndroidModule1.jAsyncTask1PreExecute(Sender: TObject; out startProgress: integer);
  80. begin
  81.    startProgress:= 0;  //out param !
  82.    LogMessage('Dialog Start');
  83.    jDialogProgress1.Start; //or Show
  84. end;
  85.  
  86.  
  87.  
  88.  
  89. procedure TAndroidModule1.jButton1Click(Sender: TObject);
  90. begin
  91.  
  92.    if not jAsyncTask1.Running then
  93.    begin
  94.      //ShowMessage('Execute ... ');
  95.      jAsyncTask1.Execute
  96.    end
  97.   else
  98.      ShowMessage('Running...');
  99. end;
  100.  
  101. procedure TAndroidModule1.LogMessage(psMsg: String);
  102. begin
  103.   __android_log_write(ANDROID_LOG_INFO,PChar(Text),PChar(psMsg));
  104. end;
  105.  
  106. procedure TAndroidModule1.RunGetUsers;
  107. var
  108.   lpUserService : UserService;
  109.   loUserArray   : TUserArray;
  110.   loUser        : TUser;
  111.   i             : Integer;
  112.  
  113. begin
  114.   LogMessage('Create proxy');
  115.   lpUserService := CreateUserProxy;
  116.   LogMessage('proxy Get List');
  117.   loUserArray   := lpUserService.GetList();
  118.   slUsers.Clear;
  119.   LogMessage('List Length ' + IntToStr(loUserArray.Length));
  120.   for i := 0 to loUserArray.Length-1 do
  121.     begin
  122.       loUser := loUserArray[i];
  123.       slUsers.Add( loUser.UserName );
  124.     end;
  125. end;
  126.  
  127. function TAndroidModule1.CreateUserProxy: UserService;
  128. var
  129.   buffsimplecall, buffTransport, buffFormat : string;
  130.  
  131.   function GetServiceURL( WebServiceAddress : String ):String;
  132.   begin
  133.     Result := WebServiceAddress   + '/services/UserService';
  134.   end;
  135.  
  136. begin
  137.   buffFormat     := 'json';
  138.   buffsimplecall := 'http:Address=' + GetServiceURL(jEditText1.Text) + '/?format=' + buffFormat;
  139.   buffTransport  := buffsimplecall;
  140.   buffFormat := buffFormat + ':';
  141.   LogMessage(buffTransport);
  142.   LogMessage(buffFormat);
  143.   Result     := TUserService_Proxy.Create( 'UserService',  buffFormat,  buffTransport  );
  144. end;
  145.  
  146.  
  147. end.
  148.  
Title: Re: LAMW and TThread
Post by: bmcsoft on December 06, 2020, 10:47:45 am
When I create TThread in LAMW, I've got black screen on my phone. I can't see main form with jButton and jEditText.

Code: Pascal  [Select][+][-]
  1. MyThread = class(TThread)
  2. private
  3.  
  4. protected
  5.   procedure Execute; override;
  6. end;
  7.  
  8. ...
  9.  
  10. procedure TAndroidModule1.AndroidModule1Create(Sender: TObject);
  11. begin
  12.     sock:=TUDPBlockSocket.Create;
  13.  
  14.     ThreadBegin := MyThread.Create (false); // ThreadBegin := MyThread.Create (true) - don't work also
  15.     ThreadBegin.FreeOnTerminate := true;
  16.     ThreadBegin.Priority:=tpNormal;
  17. end;
  18.  
  19. procedure MyThread.Execute;
  20. var
  21.   buf: string;
  22. begin
  23.     sock.Bind('0.0.0.0','15001');
  24.     if sock.LastError<>0 then exit;
  25.     while True do
  26.       begin
  27.       if terminated then break;
  28.       buf := sock.RecvPacket(1000);
  29.       if sock.lasterror=0 then
  30.         begin
  31.         le2:=sock.GetRemoteSinIP;
  32.         le3:=IntToStr (sock.GetRemoteSinPort);
  33.         AndroidModule1.jEditText1.Text:=buf;
  34.         end;
  35.       sleep(1);
  36.       end;
  37. end;

When I remove "ThreadBegin := MyThread.Create (false)" string, app starts normally and main form shows jButton and jEditText.

Help me please, I'm novice in Android and LAMW. Such code in Windows works normally with TThread.
Title: Re: LAMW and TThread
Post by: bmcsoft on December 06, 2020, 12:51:46 pm
I found the information about it: "You donĀ“t need any special unit for this to work with Windows. However with Linux, macOS and FreeBSD, you need the cthreads unit and it must be the first used unit of the project (the program source, usually the .lpr file)!".

Key words here is: "first used unit of the project is lpr-file". When I edit Unit1.pas with "use cthreads" it did not work!
Title: Re: LAMW and TThread
Post by: jmpessoa on December 06, 2020, 09:18:57 pm

@bmcsoft

Quote
Key words here is: "first used unit of the project is lpr-file". When I edit Unit1.pas with "use cthreads" it did not work!

So you are suggesting changing these lines of code from Unit*.pas to "controls.lpr" ??

Code: Pascal  [Select][+][-]
  1. {$IFDEF UNIX}{$IFDEF UseCThreads}
  2.   cthreads,
  3.   {$ENDIF}{$ENDIF}    
  4.  

If yes, I can do that!
Title: Re: LAMW and TThread
Post by: lucamar on December 07, 2020, 12:39:58 am
So you are suggesting changing these lines of code from Unit*.pas to "controls.lpr" ??
[...snip ...]

Yes; as happens with the alternative C memory manager (cmem), if used at all those units must be the very first in the uses clause of the program itself (the "lpr", in Lazarus parlance) because they need to be initialized (and the dynamic lib loaded, if needed) for any other code to be aware of it when needed, say, in the initialization of the RTL/FCL/LCL, etc.
TinyPortal © 2005-2018