Is there a good way to check if an entire application (not an activity!) is closed by the user? I want to log the time a user spends using the application, so a simple activity onPause() ,onStop() or onDestroy() is not sufficient.
There are several ways an application can be closed, either the user pressing the home button, search button or simply leaving the application. Is there a unified (eg. simple) way to see if any of these things happened?
There are several ways an application can be closed, either the user pressing the home button, search button or simply leaving the application.
Neither of these actually closes the application. The activities will continue to run unless you explicitly call finish() or the system kills them when it runs out of resources.
Why is not sufficient to use onResume() and onPause()?
will overriding finalize() to the App class (that extends Application) help for this job ?
if not , maybe a reference inside this class to another class that has this method?
Related
I know that, unlike onCreate(), Application class does not have a onDestroy() method. But I wanted to know when my application is closed (or it is not visible on screen anymore). After all, whatsapp and many more similar chat applications can detect when user has left the app, and can record user's last online time. I want to achieve a similar thing. Also, when the application is destroyed, I want to detach all listeners attached to firebase databse.
I have already seen this question, but the accepted answer there is unreliable. So, what is the workaround for onDestroy() for me.
if you are talking about Application class (detecting when it is destroyed) - this is impossible, when Application gets killed developer shouldn't (and don't) have option for executing own code (as it may e.g. restart app from scratch)
but you are talking about app visibility, probably any Activity present on screen - extend Application class (and register it in manifest) and use ActivityLifecycleCallbacks with additional counting code: counter++ when any onActivityStarted and counter-- when onActivityStopped. also in onActivityStopped check if your counter==0, if yes then all your Activities are in background, so app isn't visible on screen (still it doesn't mean that its destroyed/killed)
edit: check out THIS example. or inspect supporting class ProcessLifecycleOwner (which probably is counting visible Activities for you and only calls onAppBackgrounded when all are gone)
You do not need onDestroy callback for it . You should be Doing it in onStop() of ProcessLifecycleOwner . Upon Application destroy your process will be destroys anyways in idle situation so no need to remove listeners there .
Remove the listeners in onStop and attach again in onStart . You can configure Application class with ProcessLifecycleOwner in a way so that Every Activity gets These callbacks. This is how it should works i guess if app is in background u will pop a notification of new message . Checkout ProcessLifecycleOwner.
I have an Activity that I consider a critical operation (Specific communication with another computer over Bluetooth) and I want to make it so that when the user leaves the activity, it cannot be resumed to that state. With other words, if the user resumes the activity it should be recreated.
Since this activity uses Bluetooth it might start one or two activities for result (Enable-Bluetooth activity and Request-Permissions activity) and therefore, I cannot simply finish() the activity in onPause().
By leaving the Activity, I mean presses the home button, takes a phone call or presses the multitask button
I have experimented with some Activity Launch modes (like singleTask) without success.
I already call super.onCreate(null) in the Activity's onCreate() method, preventing it from recreating to a specific state after it has been destroyed, but I want to reset the activity whether onDestroy() has been called or not.
Does anyone have any suggestions on how this should be done correctly?
Edit:
The question in the Possible duplicate explains how to quit an application and it's subtasks completely (whereas just finish() would suit my needs perfectly - if I knew where to call it). This question is about finding a clean way to not resume the previous state of the Activity.
If you never want a state persist once you've left via the home button, or perhaps even when the screen turns off, the simplest thing is to work with the lifecycle events available. It's a whole lot simpler than trying to work around Androids design by doing things like forcing the close of your app.
Since everything needs to be setup each time someone returns to the app, you can move all of your setup logic out of onCreate and into onResume. Then, perform all the required cleanup (kill your BT connection, etc) in onPause. The only possible gotchas are related to things like changing screen rotation/ opening the keyboard which might trigger lifecycle events that you didn't intend. That might make your program less responsive if you have a lot of long running tasks on the UI thread in onResume.
Here's the situation:
I want to check if the device is rooted or not every time the app comes to foreground (either because they're launching the app through App Drawer or coming back to the app via Recent Apps list). This check is done during onResume(), and it's working well.
The problem is that the intention is to check for root only once when the app comes to foreground, not when user is currently using the app. Since onResume() is called when an Activity comes to foreground, this means the check is done multiple times even when it's not needed, which comes at performance cost.
I thought of using a static variable to lock it, locking just before I perform the check to ensure the check is only called once. This is fine and dandy, but the problem is when to do the unlock?
onPause() is called before another Activity comes to focus, which
would negate the lock. I tried to use isFinishing(), but if a user
presses the back button, the activity is destroyed, which resets the
root checking lock and renders it less desirable. EDIT: Also, the Activity is not finished if the user presses Home button, which means it's also not reliable enough
onStop() and onDestroy() are not guaranteed to be called, and
they're also called if the user presses back button.
Is there a way to call a function exactly once when the app moves to background, without restricted to the constraints of onPause() above? I searched through the Activity, Application, and BroadcastReceiver documentation but couldn't find any mention about such a thing
In the end, I decided to use a combination of onUserLeaveHint(), custom startActivity() and onBackPressed() to do it, with some private static and non-static variables
I used onUserLeaveHint() to detect when user is going back to Home
or to Recent apps list.
onBackPressed() is used to tell the app that it is used for
navigation, while another onBackPressed() override is written at the
app entry point to detect when user is using back button to go back
to Home (can't believe onUserLeaveHint() doesn't account for that)
the custom startActivity() makes sure that onUserLeaveHint() is not
called when another activity is started. While onUserLeaveHint() has issues with forced interruptions (such as user receiving a call), it is deemed acceptable for now.
I did some research and found this blog but it makes use of onStop(), which is not guaranteed to run
Thanks for all the responses. I understand the concern about my security approach, but the question is about detecting when the user is leaving the app
I have an offline-online application, i found a strange issue in it, may be it is not, but i did'nt understand about it..
App requirement is that, if internet is available, even from starting app or from resuming, i call webservices and store data in sqlite, otherwise app stays in offline mode,
I have 2 activities, second activity contains an id, that i passes through intent (that point is important),
My Problem:
if i am in second activity, and internet is running, and i press home button , then this 2nd activity pauses, then stop which is a default behavior in android, i goto settings, turn wifi off, then press app icon again to get back in my app, here i got confused, i expect that my app now will be in onResume, but when i see in logcat its onCreated called and app
crashes, nullPointerException occurs, because this 2nd activity does not have that id, i passed through intent..
Note:
If i use recent app button to go to "settings", then come back again after turing wifi off, and repeat all this behavior, then working fine, its onResumes called not oncreate..
My Question
Why it is going in onCreate while i my expectation is to be onResume while i came back from app icon?
The NPE reason is clear, your second activity doesn't have the value and it crashes.
Why do you get different behavior then!?
It's because the launching intents are different. When you "task switch" Android is merely stopping your app but leaving it there (no guarantee) in case you want to switch back.
Going home (with home) is a clear indication that you want to leave the app, and although it will remain in memory and cached (as long as there is available memory), going back through the launcher (or App Icon as you call it) fires the LAUNCHER category (which goes to your Activity 1 first).
Take a look at this StackOverflow question (and answer) to better understand the consequences.
In any case, your problem is that your app must always be designed to resume in an inconsistent state and be able to recover. Android will kill your references, will destroy your variables and most likely send your app to hell overnight even if you have it running… if the phone goes on standby, chances are processes that aren't doing anything will be paused/stopped and likely killed.
Re-design your app so this is not a problem.
You say:
"I have 2 activities, second activity contains an id, that i passes
through intent (that point is important),"
Well, why not make it easier and have ONE activity and TWO fragments? Then use Fragment Arguments to pass the value?
Or why not store the value in the preferences and/or a local database and recover it during onCreate?
And also why not make it so that if Activity 2 doesn't have a value, it calls Activity 1 and closes itself (better than a crash, huh?).
Etc.
As you can see there are multiple things you should consider. All in all, never trust that your app will be alive, because it won't.
Once your activity's onStop gets called it's susceptible to be killed by the android system to collect resources for other apps which is what i think happened in your case.If it is killed, android will obviously call OnCreate when you get back to the activity.Check this for clarification. For experimenting you can try opening more than one apps from your recent apps and then return to your app. It may crash there too now.
You stated that you can see that the activitiy is stopped (onStop) if you go to the settings. That is the behaviour shown in the Android activity lifecycle. The counterpart for onStop is onCreate. So it does what the documentation tells us. Btw activities are paused if they are visible in some way and get stopped if they are not visible anymore. This would explain why your activity get paused. For further information read Managing the Activity Lifecycle. You can find a whole picture of the lifecycle here.
This type of behaviour can be seen when you change some system configurations like font type,font size or language. But turning wifi on/off won't destroy the app and recreate it again. Check http://developer.android.com/guide/topics/manifest/activity-element.html#config for more information
I recently launched my first iPhone app and it seems to have people in the Android community asking for it ... so I started developing w/ the SDK.
The first thing I noticed is that in my iPhone app I would store certain session wide variables in the appDelegate. As I don't have this structure in Android I'm curious how Android developers keep track of application state across the app (hopefully w/out a ton of singleton objects?)
If the singleton object approach is how most developers do this - how can I ensure the application starts at a clean state each time the user clicks the "home" button and re-clicks icon (is there something I can add to my manifest to ensure it doesn't support multitasking in this way?)
My app has a lot of session specific state and for the first iteration won't yet support multitasking :(
First, android app can consist of multiple Activities.
If you want to share state between Activities use Application class: How to declare global variables in Android?
If you only have one Activity, then you can save state there.
Beware: when activity is not Active (it's GUI not showing) it does not mean that it is killed. So if you use your app and then close it, open another app, then go back to you app, it might be still "alive" (kept in memory) and the state would be preserved.
The best way to handle this is to hook into Activity lifecycle. Then you can set/reset data at will.
If you want to close the app when the user hits the "home" key, you can call finish() into your onPause method.
See this link:
Killing android application on pause
I find Singletons to be the best way to retain application state in Android applications. You can listen for when the user leaves the application through the onPause() and onStop() methods of the currently focused Activity, and do whatever you want with your data at that point. It's not good practice to try to override the OS's lifecycle management of your application (e.g. trying to kill your process when Back is pressed). If you want the app's state to reset every time the user leaves the application (via pressing Home, or being interrupted with a phone call or notification or what have you), simply put all your session data in the Activity itself. When the user leaves it will be destroyed and recreated when the user returns.
There are obviously specifics that I don't know about your application, but once you get familiar with the lifecycle of each screen (Activity) and of the application, you'll be able to use the callbacks to manage your state however you see fit.
http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle