Android 应用程序的启动和结束事件

11

我有一个跟踪用户应用程序活动的应用,包括时间等信息。现在,如果用户打开应用程序,它将启动一个会话,并且直到用户在此应用程序中,他的会话将继续。他可以切换到多个活动。与此同时,如果他切换到另一个应用程序,则他的会话日志记录应该停止并写入文件。

我的尝试:

我创建了一个基础活动,在“onResume”事件上,如果计数器为零,我开始会话并增加计数器。在“onStop”事件上,我递减计数器,并且如果计数器为零,则停止会话。

但是这样做将无法计算出实际的问题,因为Android在用户切换到另一个应用程序时不会停止活动。

那么有没有办法实现这样的功能。

另外:

如果我们能够获取应用程序活动是否在屏幕上显示的状态,那么该事件就可以用于启动或结束会话。

6个回答

6
我可以想到两种方法来完成它:
选项1:
您可以创建一个服务,扫描前台的当前应用程序并查看它是否是您的活动。以下是一些代码,您可以使用它,我从另一个答案中提取了它:

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"/>

回答链接:Android: 如何从服务中获取当前前台活动?

您可以每一秒或更短时间调用此功能以检测您的应用程序是否仍处于活动状态。请注意,根据官方文档,它已被弃用并不建议用于此类事情:

getRunningTasks()

注意:此方法仅旨在调试和呈现任务管理用户界面。这不应该用于应用程序的核心逻辑,例如根据此处找到的信息决定不同行为之间的区别。不支持此类使用,未来可能会出现错误。例如,如果多个应用程序可以同时运行,则根据此处数据的含义进行控制流程的假设将是错误的。


选项2:

第二个选项是创建一个扩展Application 的类,其中包含标志,例如isAppRunning ,根据您的应用程序是否在前台,该标志将为真或假:

public class MyAppContext extends Application {

   public boolean isAppRunning = true;

   public void setIsAppRunning(boolean v){
      isAppRunning = v;
   }

   public boolean isAppRunning(){
      return isAppRunning;
   }

}

然后,在你的AndroidManifest.xml文件中,你需要添加这个类,以便在应用程序启动时使用它。只需在应用程序标签下添加android:name=".MyAppContext"即可:

<application
        android:name=".MyAppContext"

现在,在您进行的每个活动中,您都应该重写 onResume()onPause() 方法,并将标志设置为相应的值:

class BaseActivity extends Activity {


    @Override
    protected void onResume() {
        super.onResume();
        ((MyAppContext)getApplication()).setIsAppRunning(true);
    }

    @Override
    protected void onPause() {
        ((MyAppContext)getApplication()).setIsAppRunning(false);
        super.onPause();
    }
}

每次您启动一个活动(Activity),MyAppContext 中的 isAppRunning 的值将为true。当您退出该 Activity 时,它的值将变为false。但是,如果打开了另一个 Activity(例如,如果您按下返回按钮,则返回到上一个Activity),则该值将立即再次变为true
最终,当您完成所有活动后,不会调用任何onResume()方法,而是会调用所有onPause()方法,因此isAppRunning 将变为false,您就知道您的 Activity 不再处于前台。
因此,简要概括一下,如果isAppRunningtrue,则表示应用程序在前台(开始会话跟踪),否则就不在前台(停止会话跟踪)。您可以在MyAppContext类中创建一个Timer来定期检查isAppRunning的值,如下所示:
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 () { ... };

}

根据您在会话跟踪中想要获取的精度,您应该修改timerRate


这是一个已弃用的API,不总是返回正确的值。我被迫在我的应用程序中使用它,但它并不总是有效。API文档明确提到了这一点。 - Nitin Sethi
是的,但我想不到其他跟踪活动的方法。 - Andres

2

1. 创建一个名为AppLifecycleTracker的类,并将以下内容粘贴进去。

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);
            }
        }

* 在onActivityCreate中,如果numOfCreated = 0,则可以说应用程序已启动。 *在onActivityDestroyed中,如果numOfCreated = 0,则可以说应用程序已关闭。

  1. 创建一个扩展Application的类,在onCreate中,添加以下行:

    registerActivityLifecycleCallbacks(new AppLifecycleTracker());

  2. 将应用程序名称设置为manifest.xml中的Application类。

就这样。您已经准备好了。


看起来如果一个活动同时被停止和销毁,可能存在双重递减的风险。 - user650881

2

将所有的Activity都从BaseActivity继承,像下面这样。这是最好的选择,因为无论您的Activity何时显示或离开手机屏幕,onPause和onResume方法都有保证会被调用。

class BaseActivity extends Activity {


    @Override
    protected void onResume() {
        super.onResume();
        // Start Logging
    }

    @Override
    protected void onPause() {
        super.onPause();
        // End Logging
    }
}

这是最简单(也是最好的)方法,也是大多数需要此功能的第三方API(例如Flurry)的推荐用法。 - Kasra Rahjerdi

1
你需要了解Android中的Activity生命周期。
你需要使用onPause - 可以在这里查看文档。
我还要提醒一点,即使在多个活动之间切换时也会触发onPause,因此您需要跟踪何时暂停以转到另一个屏幕。

因此,使用onPause将不会向应用程序提供有关其是否正在切换到另一个应用程序或另一个活动的信息... - Ashish Kasma
不,这只是Activity工作方式的一部分,它在Activity不再处于焦点状态时运行。当用户切换到另一个应用程序时,另一个应用程序获得前台焦点(如果您在键盘上添加单词,则会发生此情况),甚至当用户锁定设备或屏幕超时锁定设备时也会发生这种情况。 - Jamie - Fenrir Digital Ltd
我使用的方法是使用应用程序级别的变量,并在您的应用程序中切换到另一个活动时将其设置为true - 您知道这一点,因为您正在使用startActivity(Intent intent)。在所有活动的onResume方法中将其重置为false。 - Jamie - Fenrir Digital Ltd

0

现在Android提供了生命周期观察器。因此,您可以使用它。您可以在应用程序类中添加观察器以检测应用程序的状态。您可以在此链接中找到更多详细信息什么是生命周期观察器,如何正确使用?

public class MyApplication extends MultiDexApplication implements LifecycleObserver
        
        @Override
        public void onCreate() {
            super.onCreate();
        
            ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
        
        }
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void appInResumeState() {
        Toast.makeText(this,"In Foreground",Toast.LENGTH_LONG).show();
    }
    
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void appInPauseState() {
        Toast.makeText(this,"In Background",Toast.LENGTH_LONG).show();
    }
}

0

你可以轻松地通过我提到的源代码来实现这一点,该代码还可以在方向更改时保存。(参考资料)

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) {
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接