Delphi XE5 Android Thread makes app crash - android

I have a thread downloading and saving a clientDataset file cds file from a remote Datasnap Server.
This thread works in Windows, IOS (Simulator, Iphone, Ipad) but not on Android.
The app crashes after completed the file download and save it on Android.
The code is simple.
Thread:
TDownloadSaveRemoteDBThread = class (TThread)
public
Username,Password,host,port : String;
error : String;
Folder : String;
ServerMethod : String;
filename : String;
protected
procedure Execute; override;
end;
procedure TDownloadSaveRemoteDBThread.Execute;
var
sqlCon : TSqlConnection;
cds : TClientDataset;
ssm : TSqlServerMethod;
dpr : TDataSetProvider;
begin
inherited;
error :='';
SqlCon:=TSQLConnection.Create(nil);
try
sqlCon.DriverName:='Datasnap';
sqlCon.LoginPrompt:=false;
sqlCon.Params.Values['hostname']:=host;
sqlCon.Params.Values['port']:=port;
sqlCon.Params.Values['UserName']:=Username;
sqlCon.Params.Values['Password']:=Password;
try
sqlCon.Open;
cds:=TClientDataset.Create(nil);
ssm:=TSqlServerMethod.Create(nil);
dpr:=TDataSetProvider.Create(nil);
try
ssm.SQLConnection:=SqlCon;
ssm.ServerMethodName:=ServerMethod;
dpr.DataSet:=ssm;
cds.SetProvider(dpr);
cds.Open;
cds.SaveToFile(folder+filename);
cds.Close;
finally
cds.free;
ssm.free;
dpr.free;
end;
Except
on E : Exception do
Begin
error:=E.Message;
SQLCon.Close;
End;
end;
finally
SQLCon.Close;
SQLCon.free;
end;
end;
I have a button to start the thread in my mainform “Start Form”
procedure TStartForm.Button1Click(Sender: TObject);
var
DownloadSaveRemoteDBThread : TDownloadSaveRemoteDBThread;
begin
DownloadSaveRemoteDBThread:= TDownloadSaveRemoteDBThread.Create(true);
DownloadSaveRemoteDBThread.OnTerminate:= StartForm.ferdigHentDB;
DownloadSaveRemoteDBThread.Password:='test';
DownloadSaveRemoteDBThread.Username:='test';
DownloadSaveRemoteDBThread.host:=edit1.text; //127.0.0.1
DownloadSaveRemoteDBThread.port:='211';
DownloadSaveRemoteDBThread.Folder:=System.IOUtils.TPath.GetDocumentsPath + PathDelim +'db'+ PathDelim;
DownloadSaveRemoteDBThread.ServerMethod:= 'TServerMethods2.hentselect3';
DownloadSaveRemoteDBThread.filename:='select3.cds';
DownloadSaveRemoteDBThread.FreeOnTerminate:=true;
DownloadSaveRemoteDBThread.Start;
end;
Then after thread is finished I have this simple procedure
procedure TStartForm.ferdigHentDB(sender: Tobject);
begin
with sender as TDownloadSaveRemoteDBThread do
Begin
if error > '' then
Begin
showmessage(error);
End;
End;
end;
Any suggestions why Android crashes, is there an easy fix for this issue?

TThread in XE5 has two major bugs on Android. Sychronize() and Queue() are broken (Synchronize() is used to trigger the OnTerminate event), and TThread does not detach itself from the Android JVM before termination if any JNI objects are used by the thread. The first bug has not been fixed yet. The second bug is fixed in XE6, but there is a workaround you can use in XE5.

Related

Wordpress xml-rpc client using idhttp fail with EIdConnClosedGracefully on android

Basic facts:
The application was created as a multiplatform default empty application.
Wordpress is on a NonSSL connection.
On windows the code (below) works flawlessly.
On Android the data is being received by the
server flawlessly, However the application is being shut down.
Debug shows the exception IdConnClosedGracefully
The "try except" does not intercept the exception.
XE8, indy 10
Questions:
Am I doing something wrong?
Why is the exception not being intercepted.
What can I do to prevent the shutdown?
the code:
procedure TForm8.Button1Click(Sender: TObject);
var
LPostURL : String;
LXMLStream : TMemoryStream;
LHttp: TIdHttp;
begin
TTask.Run(procedure
var
LPostURL : String;
LXMLStream : TMemoryStream;
LResStream : TMemoryStream;
LHttp: TIdHttp;
begin
LHttp := TIdHTTP.Create;
LHttp.HTTPOptions := LHttp.HTTPOptions - [hoForceEncodeParams];
LHttp.HandleRedirects:=true;
buildpost;
xml.Active:=true;
LPostURL := 'http://benkyo.tk/xmlrpc.php';//edit1.Text;
LXMLStream := TMemoryStream.Create;
XML.SaveToStream(LXMLStream);
try
try
memo1.lines.text:=LHttp.post(LPostURL, LXMLStream);
except
on E:exception do
memo1.Lines.Text:=('IdHTTP1.Post error'+ E.Message);
end;
finally
LHttp.Free;
LXMLStream.Free;
end;
end);
end;

TIdTCPClient app crash on android 6

On Delphi XE8 i have simple function to check internet connection:
function TForm1.Internet: boolean;
begin
result:=false;
try
IdTCPClient1.ReadTimeout:=2500;
IdTCPClient1.ConnectTimeout:=2500;
IdTCPClient1.Port:=80;
IdTCPClient1.Host:='google.pl';
IdTCPClient1.Connect;
IdTCPClient1.Disconnect;
result:=true;
except
result:=false;
end;
end;
Everything works just fine in older android version but in andoid 6 the app just crashes (close) when i call IdTCPClient1.Connect.
Then I learned that this is blocking function and it has to be in worker thread so i wrote something like this:
type
TTest = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
end;
and in the implementation section:
procedure TThread.Execute;
begin
try
Form1.IdTCPClient1.ReadTimeout:=2500;
Form1.IdTCPClient1.ConnectTimeout:=2500;
Form1.IdTCPClient1.Port:=80;
Form1.IdTCPClient1.Host:='google.pl';
Form1.IdTCPClient1.Connect;
Form1.IdTCPClient1.Disconnect;
except
showmessage('no internet connection');
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
Test : TTest;
begin
Test := TTest.Create(False);
end;
but unfortunately the app is still closing on android 6 when i call TForm1.Button1Click (on windows and older android versions works just fine)
Please help me ;)

Write into the SQLite database from an Android service in Delphi (RAD Studio)

I have an Android application and service in the same process. Write code under RAD Studio Delphi 10.1.
I need to get geographic coordinates in Android Service (that I'm doing well) and write them to the SQLite database.
And from time to time the application can (when the user needs) process the coordinates in the user interface.
When I put TConnection (any - ADO, FireDAC, UniDAC) into DataModule not even make an active connection, the service stops working, even not running the OnStartCommand event.
Monitor.bat shows no obvious errors.
Please tell me how to work with a SQLite database in Android Service and it Android Application at the same time.
I found a solution:
I updated UniDAC components for Berlin to latest version (6.3.12).
TUniConnection and TUniQuery well work with SQLite in Android Service.
Add to Project->Deployment of the host application my SQLite DB-file, Remote Path sets to ".\assets\internal\".
I hope this code will useful for you.
procedure TDM.conSQLiteBeforeConnect(Sender: TObject);
begin
{$IF DEFINED(iOS) or DEFINED(ANDROID)}
conSQLite.Database := TPath.Combine(TPath.GetDocumentsPath, 'mybase.sqlite');
{$ENDIF}
end;
procedure TDM.conSQLiteError(Sender: TObject; E: EDAError; var Fail: Boolean);
begin
Log('--- DB error: %s:', [E.Message]);
Fail := False;
end;
function TDM.AndroidServiceStartCommand(const Sender: TObject; const Intent: JIntent; Flags, StartId: Integer): Integer;
begin
Log('+ START with Intent: ' + JStringToString(Intent.getAction.toString), []);
if Intent.getAction.equalsIgnoreCase(StringToJString('StopIntent')) then
begin
try
conSQLite.Disconnect;
Log('- DB disconnected', []);
except
on E: Exception do
Log('- can not to disconnect DB', [E.Message]);
end;
Log('... service to be stoped', []);
JavaService.stopSelf;
Result := TJService.JavaClass.START_NOT_STICKY; // don't reload service
end
else
begin
Log('... service started', []);
try
conSQLite.Connect;
Log('+ DB connected', []);
UniQuery.SQL.Text := 'select count(*) as ALLREC from orders';
UniQuery.Open;
if UniQuery.RecordCount > 0 then
begin
UniQuery.First;
Log('... record count: %s', [UniQuery.FieldByName('ALLREC').AsString]);
end;
UniQuery.Close;
except
on E: Exception do
Log('- can not to connect DB: %s', [E.Message]);
end;
Result := TJService.JavaClass.START_STICKY; // rerun service if it stops
end;
end;
I have struggled the same issue but I started to use TSQLConnection (dbexpress) component with TSQLQuery (dbexpress) component and these are components wrok well in Android service.

Can Delphi Firemonkey TControl.MakeScreenshot work in a thread?

I've created a simple FireMonkey screenshot capture that works fine on Android and Windows..:
procedure Capture;
var
B : TBitmap;
begin
try
B := Layout1.MakeScreenshot;
try
B.SaveToFile( ..somefilepath.png );
finally
B.Free;
end;
except
on E:Exception do
ShowMessage( E.Message );
end;
end;
end;
when I moved it to a thread as below, it works fine in Windows but in Android I get the exception 'bitmap too big' from the call to MakeScreenshot. Are there additional steps needed to employ MakeScreenshot in a thread?
procedure ScreenCaptureUsingThread;
begin
TThread.CreateAnonymousThread(
procedure ()
var
B : TBitmap;
begin
try
B := Layout1.MakeScreenshot;
try
B.SaveToFile( '...somefilepath.png' );
finally
B.Free;
end;
except
on E:Exception do
TThread.Synchronize( nil,
procedure ()
begin
ShowMessage( E.Message );
end );
end).Start;
end;
Later addition. Based on suggestions by Sir Rufo and Sebastian Z, this solved the problem and allowed use of a thread:
procedure Capture;
begin
TThread.CreateAnonymousThread(
procedure ()
var
S : string;
B : TBitmap;
begin
try
// Make a file name and path for the screen shot
S := '...SomePathAndFilename.png';
try
// Take the screenshot
TThread.Synchronize( nil,
procedure ()
begin
B := Layout1.MakeScreenshot;
// Show an animation to indicate success
SomeAnimation.Start;
end );
B.SaveToFile( S );
finally
B.Free;
end;
except
on E:Exception do
begin
TThread.Synchronize( nil,
procedure ()
begin
ShowMessage( E.Message );
end );
end;
end;
end).Start;
end;
MakeScreenShot is not thread safe, so you cannot safely use it in a thread. If this works in Windows then I'd say you were just lucky. I'd suggest that you take the screenshot outside of the thread and only use the thread for saving the screenshot to png. Painting should be fast while encoding to png needs a lot more resources. So you should still benefit pretty much from the thread.

Synchronize of thread cause deadlock?

The same project runs perfect on Windows/iOS platform, but cause deadlock on Android (two different android devices) after running for uncertain duration.
procedure TTestThread.FSynProc;
begin
Inc(Form1.FExecuted); //Variable of TForm
Form1.Text1.Text:= IntToStr(Form1.FExecuted);
end;
procedure TTestThread.Execute;
var
begin
while not Self.Terminated do
begin
Self.Synchronize(FSynProc);
sleep(10);
end;
end;
constructor TTestThread.Create;
begin
inherited Create(True);
Self.FreeOnTerminate:= True;
end;
destructor TTestThread.Destroy;
begin
inherited;
end;
code for launch TTestThread
procedure TForm1.StartTTProc;
begin
ftt:= TTestThread.Create; // Variable of TForm
ftt.Start;
end;
After StartTTProc, the number shows in 'Text1' increase continusely.
After running for an uncertain duration on android device, App freezed.
any advice?

Categories

Resources