I have an app which track user activity on app which include time etc, Now if user has opened the app, It will start an session and till user in this app , his session will cont
Extend all your Activities from BaseActivity like below. This is the best option for you as onPause and onResume methods are guaranteed to be called whenever your Activities show up or go away from phone screen.
class BaseActivity extends Activity {
@Override
protected void onResume() {
super.onResume();
// Start Logging
}
@Override
protected void onPause() {
super.onPause();
// End Logging
}
}
I can think of two ways of doing it:
You can create a service which scans for the current application on the foreground and see if it is your activity. Here is some code you can use, I took it from another answer:
There's an easy way of getting a list of running tasks from the ActivityManager service. You can request a maximum number of tasks running on the phone, and by default, the currently active task is returned first.
Once you have that you can get a ComponentName object by requesting the
topActivity
from your list.Here's an example.
ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE); // get the info from the currently running task List< ActivityManager.RunningTaskInfo > taskInfo = am.getRunningTasks(1); Log.d("topActivity", "CURRENT Activity ::" + taskInfo.get(0).topActivity.getClassName()); ComponentName componentInfo = taskInfo.get(0).topActivity; componentInfo.getPackageName();
You will need the following permission on your manifest:
<uses-permission android:name="android.permission.GET_TASKS"/>
Link to the answer: Android: How can I get the current foreground activity (from a service)?
You can call this every one second or less to detect if your app is still active. Please note that it is a deprecated and is not recommended for using for this kind of things, according to official documentation:
getRunningTasks()
Note: this method is only intended for debugging and presenting task management user interfaces. This should never be used for core logic in an application, such as deciding between different behaviors based on the information found here. Such uses are not supported, and will likely break in the future. For example, if multiple applications can be actively running at the same time, assumptions made about the meaning of the data here for purposes of control flow will be incorrect.
The second option is to create a class that extends Application
with a flag, for example isAppRunning
, which will be true or false according if your application is on the foreground or not:
public class MyAppContext extends Application {
public boolean isAppRunning = true;
public void setIsAppRunning(boolean v){
isAppRunning = v;
}
public boolean isAppRunning(){
return isAppRunning;
}
}
Then on your AndroidManifest.xml
you have to add this class so it will be used when your application starts. Just add android:name=".MyAppContext"
under the application tag:
<application
android:name=".MyAppContext"
Now in every activity that you have you should override onResume()
and onPause()
and set the flag to the corresponding value:
class BaseActivity extends Activity {
@Override
protected void onResume() {
super.onResume();
((MyAppContext)getApplication()).setIsAppRunning(true);
}
@Override
protected void onPause() {
((MyAppContext)getApplication()).setIsAppRunning(false);
super.onPause();
}
}
On this way every time you start an Activity the value of isAppRunning
in MyAppContext
will be true
, when you exit the Activity
it will be false
but if another Activity opens (for example if you pressed the back button so you are returning to the previous activity) the value will be immediately true
again.
When you finally finish all your Activities none of the onResume()
methods will be called and all the onPause()
methods will be called so isAppRunning
will be false
and you know your Activity
is no longer on the foreground.
So resuming, if isAppRunning
is true
your application is on the foreground (start the session tracking) otherwise it's gone (stop the session tracking). You can create a Timer
in MyAppContext
class to check the value of isAppRunning
periodically, so it would be:
public class MyAppContext extends Application {
public boolean isAppRunning = true;
public final int timerRate = 500; // Execute timer task every 500mS
public void setIsAppRunning(boolean v){
isAppRunning = v;
}
public boolean isAppRunning(){
return isAppRunning;
}
@Override
public void onCreate() {
super.onCreate();
Timer mTimer = new Timer();
mTimer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if(isAppRunning) startSesionTracking();
else stopSesionTracking();
}
}, 0, REFRESH_TIME);
}
private void startSesionTracking () { ... };
private void stopSesionTracking () { ... };
}
You should modify timerRate
according to the precision you want to get in your session tracking.
You can easily do this by the source code below I mention which is also saved from orientation change . (Reference)
public class ApplicationEventTracker implements Application.ActivityLifecycleCallbacks {
private int activityReferences = 0;
private boolean isActivityChangingConfigurations = false;
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
}
@Override
public void onActivityStarted(Activity activity) {
if (++activityReferences == 1 && !isActivityChangingConfigurations) {
// App enters foreground
}
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
isActivityChangingConfigurations = activity.isChangingConfigurations();
if (--activityReferences == 0 && !isActivityChangingConfigurations) {
// App enters background
}
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
You need to look into Activity lifecycles on Android.
What you need is onPause
- see the documentation here
I would also mention that onPause is fired even when switching between multiple activities, so you'd need to track when it's pausing to go to another screen.
1.Create a class named AppLifecycleTracker and paste this.
private class AppLifecycleTracker implements ActivityLifecycleCallbacks {
private int numStarted = 0;
private String TAG = "AppLifecycleTracker";
private int numOfCreated = 0;
@Override`enter code here`
public void onActivityCreated(Activity activity, Bundle bundle) {
if (numOfCreated == 0) {
Log.d(TAG, "onActivityCreated: app started");
}
numOfCreated++;
Log.d(TAG, "onActivityCreated: " + numOfCreated);
}
@Override
public void onActivityStarted(Activity activity) {
if (numStarted == 0) {
// app went to foreground
Log.d(TAG, "onActivityStarted: foreground");
}
numStarted++;
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
numStarted--;
if (numStarted == 0) {
// app went to background
Log.d(TAG, "onActivityStarted: background");
}
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
numOfCreated--;
Log.d(TAG, "onActivityDestroyed: " + numOfCreated);
}
}
* in onActivityCreate if numOfCreated = 0, then you can say app has started. * in onActivityDestroyed if numOfCreated = 0, then you can say app is closed.
Create a class extending Application, in onCreate, add this line
registerActivityLifecycleCallbacks(new AppLifecycleTracker());
set application name as the Application class in manifest.xml
Thats it. You are good to go.