Problem
The Android
pause
and
resume
events are not executed when the application is paused and resumed.
Note that these events fire as expected using version 1.7.5
Test case
Start the application. The OnAppResume function executes as expected. *The OnAppPause function executes unexpectedly.*
Pressing the Android Home button pauses the application. However, *the OnAppPause function does not execute.*
Pressing the applications icon on the Apps screen resumes the application. However, *the OnAppResume function does not execute.*
Pressing the Android Back button ends the application and the OnAppDestroy function executes as expected. However, *the OnAppPause function does not execute.*
Titanium.UI.setBackgroundColor('#000');
var win1 = Titanium.UI.createWindow({
title:'Test',
backgroundColor:'#fff',
fullscreen:true,
exitOnClose:true});
function OnAppResume()
{
Ti.API.info('***---> OnAppResume');
}
function OnAppPause()
{
Ti.API.info('***---> OnAppPause');
}
function OnAppDestroy()
{
Ti.API.info('***---> OnAppDestroy');
}
win1.open();
Ti.Android.currentActivity.addEventListener('resume', OnAppResume);
Ti.Android.currentActivity.addEventListener('pause', OnAppPause);
Ti.Android.currentActivity.addEventListener('destroy', OnAppDestroy);
Still investigating, but I'm generally surprised to see it works in 1.7.5 (and I've run it in 1.7.5 to verify that.) My expectation would have been that this would not have worked in 1.7.5. Window opening (the call to
win1.open()
in this case) is asynchronous. It switches from a runtime thread (which is what you're on when you callopen()
) to the UI thread (which is required to get view elements like a window up on screen). Since it's async, I would actually expect that if the next line afteropen()
is grabbingTi.Android.currentActivity
, then it's going to get the Activity that runs app.js, meaning the "root" activity, rather than the Activity that will be created to service the new heavyweight window. Indeed, this is what is happening in 1.8.0.1. In other words, the 1.8.0.1 behavior is what I would expect. Interesting that it differs from 1.7.5. Still looking...After reading Bill's comment, I'm wondering if this (
Ti.Android.currentActivity.addEventListener('pause', OnAppPause)
) is the correct way to detect the "pause" of an app on Android? Note that we're talking about pausing the whole app, like when the Android "Home" button is pressed.BTW, I believe the proper approach for that particular use case is to concentrate more on being sure to get the new window's Activity (i.e., using
win1.activity
) rather than the "current activity" at the time app.js is being processed. For example, this re-write achieves that:The only thing you'd miss out on for that is the very first resume event, since that happens just before the window open event is fired. But of course the window open event itself can stand in its place for that purpose. You still get the resume events you would expect when you, for example, pop over to the home screen and pop back again. And of course you get the pause and destroy events when expected. The reason that I find this approach "more correct" is that it distinguishes between "the current activity when all this code in app.js is running" (so to speak :)) and "the activity I'm really interested in, which is the one belonging to this heavyweight window i'm creating as the main window of my application." Nevertheless it's still interesting that the original fail case above worked in 1.7.5, and i'll be discussing with my colleagues tomorrow. Meanwhile I think my example in this comment is probably a sufficient work around for most use cases.
There's no concept of an application pause in Android. Only at the activity level. There are definitely pure native (i.e., non-Titanium) Android developers out there who are desperate for such a feature, i.e., knowing when the whole darn app goes in the background. Some resort to trying to keep an integer at the application level (in their Application class) and incrementing/decrementing when activities resume/pause. Then when the number hits 0, they wait a while to see if another activity is opening, then check the number again. If the number is still 0 at that point, they assume the whole app has been backgrounded (i.e., all activities have been paused, not just the ones below the topmost.) Horrible hack! :) It's usually suggested that they re-architect their apps to not need to know this information. Needless to say, not everybody is satisfied with that suggestion. But the fact remains, it's simply not supported in Android. Of course, if you architect a Titanium app so that it only uses one Activity, you can just rely on the listeners for that activity. When wanting to open other windows above that heavyweight window, you can open these subsequent windows as "lightweight" windows. The one big thing you lose by doing that is the back button functionality, since back button by default closes the current activity, and that's going to close your heavyweight window as well, not just your light window that you've put atop it. But in Titanium we've given you a way to hook into the back button (see the
android:back
event on [Titanium.UI.Window](http://developer.appcelerator.com/apidoc/mobile/latest/Titanium.UI.Window-object#events)). So if you intercept the back button while you're lightweight window is open, you can then just.close()
the window and fall back to the heavy. Of course, there might be other reasons you have for wanting a multiple-activity application in Titanium, besides back button functionality. You may want one window to be fullscreen and navbarhidden, but another to be just navbarhidden, or something like that. In those cases, it's going to be very hard to know when the whole app goes in the background.The work around Bill mentions is the correct route for this kind of behavior due to how native Android apps are structured. The current activity is associated with the url for the JS file where Ti.Android.currentActivity is used so the new window opened will not be tied to the current activity within the current url. The Ti.UI.Window.activity property should be used for accessing the activity associated with the window. A factory mechanism can be used to make handling this per activity easier. For example, call a method such as the one shown below inside the open event listener for a heavy weight window with the argument Ti.UI.Window.activity:
Closing issue Tested with Ti Studio build 1.0.8.201201262211 Ti Mob SDK 1.8.1.v20120127173134 OSX Lion Droid 3 OS 2.3.4, Android Emulator 2.2.2 Verified that the expected behavior of pause, resume, and destroy work correctly