We ran into an issue with ngOnDestroy not being called when we use the Android back button.
I've provided a sample application:
https://github.com/dennis-montana/back-button-issue
If you run the app on Android and click the back button you can see that ngOnDestroy isn't called while the native activityDestroyedEvent from Android is being called.
The app is still running in a sleeping state so everything created in ngOnInit is being created again every time a user uses the back button.
If you run the demo app you can see the following output:
### Opened the app 1st time
JS: AppComponent ngOnInit
### Clicked back button
JS: Android activity destroyed
### Opened the app 2nd time
JS: handleResumeEvent
JS: AppComponent ngOnInit
### Clicked back button
JS: Android activity destroyed
JS: Android activity destroyed
### Opened the app 3rd time
JS: handleResumeEvent
JS: handleResumeEvent
JS: AppComponent ngOnInit
### Clicked back button
JS: Android activity destroyed
JS: Android activity destroyed
JS: Android activity destroyed
As you can see the calls are being stacked.
@dennis-montana @spike1292
The observed behaviour is by design and expected as documented here
With
router-outletnew instance of the component is created with each navigation and is destroyed when you navigate to another component. The component's constructor and its init hooks will be called every time you navigate to the component and ngOnDestroy() will be called every time you navigate away from it.With
page-router-outletwhen you navigate forward, the current page and views are saved in the native navigation stack. The corresponding component is not destroyed. It is cached, so that it can be shown when you go back to the same page. It will still be connected to the views that were cached natively.
@NickIliev thank you for your reply.
I've read the documentation you've send but it isn't completely clear to me how it describes the Android back button behaviour when there isn't really a component to go back to. When you click back you go the the android home screen.
So when I click back I expect ngOnDestroy to be called or ngOnInit shouldn't be called when I open the app.
Could you elaborate on how to solve this issue?
@dennis-montana perhaps, instead of the Angular life hooks, you can use the NativeScript application events for this case (or directly the Android events).
I think the solution to that is to handle the activity-destroyed application event and actually kill the angular application when the event is fired. This should call the ngOnDestroy hook for all active components.
I solved this in our app by directly using the Android application event to call ngOnDestroy.
android.on(AndroidApplication.activityDestroyedEvent, (args: AndroidActivityEventData) => {
if (args.activity.toString().startsWith('com.tns.NativeScriptActivity')) {
this.ngOnDestroy();
}
});
Hi @dennis-montana ,
Facing the same issue you described above, where exactly have you declared this event ?
@hdrdiab you can place this within your app.component.ts.
For now i've placed it inside the ngOnInit method, and it is working fine.
Hi,
The solution @dennis-montana proposed is not working anymore for me.
My component have multiple child components in its view , calling ngOnDestroy on the parent component isn't destroying the children.
Can we can expose the clearCache() method of the NSRouteReuseStrategy ? I think using it will get us a reliable way to kill the angular application.
Status on this issue?
@nuvoPoint
This is still an issue.
We've run into it in our application.
I've created a test project here:
https://github.com/m-abs/tns-ng-app-lifecycle
Steps to reproduce:
tns run android --emulator --bundle --env.aotngOnInit() logged to console for the components.ngOnDestroy() is NOT logged to the console.Now if you run npm run apply-patch (this requires bash) and repeat.
Now after step 3 you should see the ngOnDestroy() in the console.
I wrote an article about this. I solved it in generic way with the decorator.
Most helpful comment
I solved this in our app by directly using the Android application event to call ngOnDestroy.