Please follow the steps below:
Create New Firemonkey Moblie Application
Add TGeustureManager component to the Form
Add 2 TButton components to the Form
Button1.Text: "Button1: Do something..."
Button2.Text: "Button2: Exit Application..."
Double click on Button2 Component and write the following code for OnClick Event:
procedure TForm1.Button2Click(Sender: TObject);
begin
if MessageDlg('Are you sure you want to Exit?', TMsgDlgType.mtWarning,
[TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0) = mrYes then
SharedActivity.finish;
end;
Run the application in debug mode.
on the device, click the button 2, then click yes to the popped up message. An exception will appear:
Why is this exception raised?
I thought it is related to unused TGeustureManager component. but NO it is NOT:
If you open the Location Demo project that comes with Delphi xe5.
Add TButton component to Location Label as shown in the image below:
Add the same code as above to OnClick Event.
Run the application, and click on Button5, you will get the same exception.
Is this a bug should I report? or am I doing something wrong?
Possibly that you are killing the activity that is running, before its execution flow has been exhausted, thereby causing problems. Much like freeing a form in a form method....
What happens if you replace:
SharedActivity.finish
with:
uses
FMX.Helpers.Android;
...
CallOnUIThread(procedure begin SharedActivity.finish end);
[ Typed from memory, so may need some tweaking ]
I have contacted Embarcadero for this issue.
They said that it is because TApplication.Terminate is not yet implemented in FireMonkey platform for mobile.
They open a ticket to implement TApplication.Terminate in nex hot fix.
Let's hope that will not take ages.
if you want only to close application un can try this:
case MessageDlg('Close Application?', System.UITypes.TMsgDlgType.mtInformation,
[
System.UITypes.TMsgDlgBtn.mbYes,
System.UITypes.TMsgDlgBtn.mbNo
], 0) of
{ Detect which button was pushed and show a different message }
mrNo:
showmessage('');
mrYes:
halt;
end;
I have the same error on a very simple Location test app, it happens when setting text on a label. The label was set to auto size, and when I changed it to a static size the error went away.
Delphi XE6, line 681 in FMX.TextLayout.GPU
I am using a Samsung S4 phone.
procedure TForm_StayTogether.LocationSensor1LocationChanged(Sender: TObject;
const OldLocation, NewLocation: TLocationCoord2D);
begin
DistLabel.Text:= FloatToStr(LocationSensor1.Distance);
AccLabel.Text:= FloatToStr(LocationSensor1.Accuracy);
LatLabel.Text:= FloatToStr(NewLocation.Latitude);
LonLabel.Text:= FloatToStr(NewLocation.Longitude);
end;
I've just experienced something similar, a very tiny app with little code giving this same error (Segmentation fault 11) every single time I quit the app on the Android device (Galaxy Note 2 in my case).
For what it's worth, the problem disappeared when I went to the Stylebook I had earlier put on the form and cleared it. I think I had earlier copied that Stylebook from another test unit.
Mike
Related
Working on a Project and stuck in an Issue:
Hardware Back Button Reloading Application (I am using Angular Router in this application).
My Code to Exit Application:
ionViewDidEnter(){
this.subscription = this.platform.backButton.subscribe(()=>{
navigator['app'].exitApp();
});
}
ionViewWillLeave(){
this.subscription.unsubscribe();
}
While same logic Working in other applications. but in this application its reloading the application not exiting it.
P.S: i have also tried it to put in platform.ready() but no luck.
With IONIC 4, there is new method subscribeWithPriority developed to handle race between soft & hard back button. Try modifying your code like below:
this.platform.backButton.subscribeWithPriority(1, () => {
navigator['app'].exitApp();
});
subscribeWithPriority() stops the propagation of the event after its execution and if we subscribe with high priority and execute our prefered navigation instead of default one then it is going to work as you want.
More reference docs for details:
https://github.com/ionic-team/ionic/commit/6a5aec8b5d76280ced5e8bb8fd9ea6fe75fe6795
https://medium.com/#aleksandarmitrev/ionic-hardware-back-button-nightmare-9f4af35cbfb0
UPDATES:
Try using this new version of exitApp cordova plugin. I haven't
tried myself but looks promising from popularity.
Also try to empty the page stack from Navcontroller or go to your home screen, seems like that's causing the reload for app with sidemenu's & tab pages... this.navCtrl.pop() / this._navCtrl.navigateBack('HomeScreen'), and then call exitApp.
NOTE: Tabs & SideMenu as those have its own routing module does create lot of complexity with app navigation.
Solved:
As Mention by #rtpHarry template of SideMenu / Tabs have History which leads application to Reload it self on root page. i was able to solve this by clearing History.
ionViewDidEnter(){
navigator['app'].clearHistory();
}
on Your Root Page just Clear your history and your Hardware Back Button will close the Application instead of Reloading it.
Do you have a sidemenu in your app? I'm just curious because this seems to be when I get this problem as well.
If you look in your inspector, you will see that window.history has a length of 1.
I don't see it in some of my apps, but the app that I have a side menu setup acts this way - on the homepage if you press back the screen goes white then it reloads the app.
Like I say, looking in the inspector shows that there is a history to step back to, which it is trying to do, and whatever that history step is, it just pushes it forward back to the homepage, which made me wonder if it was the sidemenu setting up its own control of the navigation system.
I've probably said some poorly worded terminology but as I haven't solved this myself I thought I would just let you know what I had found... hopefully it helps you move forward.
In my scenario, I wasn't even trying to do the exit on back code - I just noticed that the app would appear to "reboot" if I kept pressing back.
This explain the solution on Ionic 5 (and 4.6+ too I think).
private backButtonSub: Subscription;
ionViewDidEnter() {
this.backButtonSub = this.platform.backButton.subscribeWithPriority(
10000,
() => {
// do your stuff
}
);
}
ionViewWillLeave() {
this.backButtonSub.unsubscribe();
}
also keep
IonicModule.forRoot({
hardwareBackButton: true
}),
to true (default) in your app.module.ts
Sources:
https://www.damirscorner.com/blog/posts/20191122-CustomizingAndroidBackButtonInIonic4.html
The Doc
I'm programming apps in Android with Delphi 10 Seattle and I found a problem...
I need to show a form and in this form I'll use a variable and set a value in it but after the form.show I'll continue using this variable to calculating it and get the value that I need.
The problem is that when the form shows the function continue before the user typing the value and press the confirm button on form and it's causing a problem with the results.
I already tried to use a inputbox but its cause the same problem.... It's interesting because in Delphi XE6 I had the same code and its work perfectly.
When I tried to search a solution I found a non-blocking that was implemented in Delphi XE7 forward.
Here a dumb example to be easily to understand what I wanted to do:
procedure TfrmForm.Button1Click(Sender: TObject);
var
vExample, vResult: Integer
begin
frmForm1.Edit1.Text := '';
frmForm1.Show;
if Length(form.Edit1.Text) = 0 then
vExample := 0
else
vExample := StrToInt(form.Edit1.Text);
vResult := vExample * 5;
ShowMessage('The result is ' + IntToStr(vResult));
end;
The problem is that always show 0 in the message and I don't know how to solve this problem...
When I open my form for the first time I get no violation, but when I first select a TEdit field and then close the form and then recreate the form and open it I get the Violation.
Code for creating the form:
procedure TfrmNocoreDKS.actConfigExecute(Sender: TObject);
var
confForm: TConfiguratie;
begin
confForm := TConfiguratie.Create(nil);
confForm.ShowModal(
procedure(ModalResult: TModalResult)
begin
confForm.DisposeOf;//Also tried confForm.Free;
end);
end;
I've also tried this for creating the form:
procedure TfrmNocoreDKS.actConfigExecute(Sender: TObject);
var
confForm: TConfiguratie;
begin
confForm := TConfiguratie.Create(nil);
try
confForm.ShowModal(
procedure(ModalResult: TModalResult)
begin
end);
finally
confForm.free;
end;
end;
Code for Closing the form:
procedure TConfiguratie.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := TCloseAction.caFree;
end;
Because the violation only appears when you click on any TEdit and then close the form I think it has something to do with the virtual keyboard, but i'm not sure. I don't have any methods that use the virtual keyboard itself.
Update
While my suggestions here are as documented, there are still problems with Android and multiple forms. See later in this post.
Do not call DisposeOf() or Free at all. The FormClose() and the caFree call is the key to make it work.
The documentation how to dispose of a modal dialog has been changed: Using FireMonkey Modal Dialog Boxes.
The FireMonkey architects has struggled with this for several versions now, and finally it works.
Example from doc how to create a modal dialog:
procedure MyCurrentForm.MyButtonClick(Sender: TObject);
var
dlg: TMyModalForm;
begin
// Create an instance of a form.
dlg := TMyModalForm.Create(nil);
// Configure the form. For example, give it a display name.
dlg.Caption := 'My Modal Dialog Box';
// Show your dialog box and provide an anonymous method that handles the closing of your dialog box.
dlg.ShowModal(
procedure(ModalResult: TModalResult)
begin
// Do something.
end
);
end;
And to free your modal dialog:
procedure TMyModalForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := TCloseAction.caFree;
end;
Update
The OP has tried this solution and it does not work as expected.
Looking into QC, there are reports claiming that this does not work as expected on mobile android platforms:
RSP-9692 Runtime creation of forms in Android
and
RSP-9665 Access Violation in FMX.Platform.Android SendCMGestureMessage.
(You must login to access them).
The latter explains what is happening. When the modal form is destroyed, it is possible that FFocusedControl points to a destroyed control. When ARC is trying to release FFocusedControl this will cause a segmentation fault. FFocusedControl must be declared [weak]. See the RSP-9665 for more details.
There is also QC-126524 [Android] Open/Close/Free sub form multiple times may cause crash on Android Platform when removing Focus from TEdit reporting the same thing and closed as resolved in XE7. This apparently not true.
Embarcadero documentation regarding FMX ShowModal and mobile platforms says
Caution: Modal dialog boxes are not supported in Android apps. Instead of calling ShowModal, you should call Show, and have the form return and call your event. We recommend that you not use modal dialogs on either of the mobile platforms (iOS and Android) because unexpected behavior can result. Not using modal dialogs eliminates potential problems in debugging and supporting your mobile apps.
This issue seemed to be only accuring in Delphi XE7. I am now using Delphi XE8 and don't have this problem anymore.
On Android, when I touch the screen during a long function (required time > 30 sec) 15sec after the click, a message "Application isn't responding" appears.
I don't want to see it.
I did a test project, with 2 buttons and a function "LongProcess" for simulate a long process (it's just a sleep of 30 sec). My first button "LaunchFunction" just call the function. My second button "LaunchThread", launch a Thread who will execute my "LongProcess".
In the first case I have my problem but in the second case it works perfectly (the message will never appears because my main form is not waiting).
However, I have to wait the end of "LongProcess" (therefore the end of the Thread) because I have to do others things after it who need the result of the "LongProcess". So I tried to wait my Thread with many methods. I tried with the "WaitFor" of TThread Class but it repeat the initial problem. I tried also with a simple "while".
while not fThread.Finished do
begin
Sleep(500);
end;
But it's the same, if i touch the screen the popup will appears again.
Critical Section instead of the "while" or the "Thread.WaitFor" did exactly the same.
So I tried to update the GUI in my "while" for show to Android that the application is working.
while not fThread.Finished do
begin
Sleep(100);
Label_Test.Text := 'Msg' + IntToStr(i);
Inc(i);
Application.ProcessMessages;
end;
I see my label value change, if I touch the screen nothings change. 15sec later I will have the popup (but I will still see my label be updated on the background).
Someone have an idea ? Maybe can we disable event during a long process (so the click will not be in the queue so he should not be considered like "not responding" after 15 sec). Application.ProcessMessage don't seems works about that on Android.
Or maybe something in the Android API exists for say to the OS we are not inactive ?
For finish, if I click on "Wait" the application will work perfectly. If I don't touch the screen also (w/o thread too, until I don't touch the screen), but I see so many user click on "OK" like a robot (this close the application ofc...). Ty for your futur help
ps : I tried to replace the thread by a timer because I saw it on a forum, but it changed nothings.
ps2 : Here a .zip or the demo project http://www.partage-facile.com/YOJT1A8CLE/testproject.rar.html
If you block the main thread for too long, you will get an ANR. There's no way around it. Don't try to make your app wait. Just initiate your "other things" at the end of the LongProcess in the separate thread.
What you can try is use a Timer to operate it, but that will just be a very stupid thing to do, Android is overall slow, but this is your mistake. There really isnt a way around it with the way you are trying. You can try and declare an OnTerminate event for the thread to notify the main thread that the work is completed or find a different way without Sleep()
Normally without having to code the android back button functions and lets you got back to the previous form. In my app i'm working on instead of going back it shuts down the application. I also tried handling the back button by code but this also didn't work, it ignored the code!
Here is the code I used to handle the backbutton:
procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word;
var KeyChar: Char; Shift: TShiftState);
var
FService: IFMXVirtualKeyboardService;
begin
if Key = vkHardwareBack then
begin
TPlatformServices.Current.SupportsPlatformService
(IFMXVirtualKeyboardService, IInterface(FService));
if (FService <> nil) and (TVirtualKeyboardState.Visible
in FService.VirtualKeyBoardState) then
begin
// Back button pressed, keyboard visible, so do nothing...
end
else
begin
// Back button pressed, keyboard not visible or not supported on this platform
close;
end;
end;
end;
I used to use Delphi XE5 and now I use XE6 and hoped the problem was solved but regrettingly not. Also the above code is for the Delphi XE6 version, for XE5 it is slightly different.
UPDATE:
I've found a fix for my problem. But my delphi still reacts really strange. When I create a new project and add the files from my previous project i'm able to go back with the android backbutton. But as soon as I save the project again and then try to run it then it stops working.
The back button has a special function in the android framework- onBackPressed(). I don't know if it was ported to Delphi, but I assume so. It won't come through that API
After creating a new project in a new directory and then adding all the files too the project the issue had dissapeared! The problem seemed to be somewhere in de dproj file. I tried too find it, but it was to big for me to locate it.
You need to trap the "Back" keypress in your FormKeyUp procedure so that it isn't passed to the operating system after you act on it:
if (Key = vkHardwareBack) then
begin
Key := 0;
{ Do something else }
end;