【问题标题】:Automatically log Android lifecycle events using ActivityLifecycleCallbacks?使用 ActivityLifecycleCallbacks 自动记录 Android 生命周期事件?
【发布时间】:2012-05-15 18:07:16
【问题描述】:

我正在尝试使用 ActivityLifecycleCallbacks 自动捕获和记录 Android 生命周期事件,但至少可以说,这方面的文档很少:

    public void registerActivityLifecycleCallbacks (Application.ActivityLifecycleCallbacks callback)

我不想扩展 Activity 类或覆盖现有的生命周期方法(onCreate、onResume 等),我希望有一个单独的类来监听这些事件并采取相应的行动。

有没有人有这方面的经验,或者有关于它如何工作的可靠文档或教程的链接?具体来说,ActivityLifecycleCallbacks如何注册,如何处理?

【问题讨论】:

  • 更新:标准 API 现在已经存在了足够长的时间,以至于 @ClarkXP 的 roll-your-own 对于大多数应用程序来说都是多余的。相反,请参阅@Jeroen 的答案。我将其总结/澄清为“在您的回调类(具有implements Application.ActivityLifecycleCallbacks)中,在其构造函数中执行getApplication().registerActivityLifecycleCallbacks(this); 如果您的类具有onCreateinit 或在实例激活时运行的类似方法,请将该行在那里而不是在构造函数中(因为该类可能在完全准备好之前不希望接收回调)。”

标签: java android callback lifecycle


【解决方案1】:

我没有任何第一手经验,但从 API 来看,您可以编写自己的实现 Application.ActivityLifecycleCallbacks 接口的类,然后在提供的 Application 类实例上注册该类

getApplicaton().registerActivityLifecycleCallbacks(yourCustomClass);

此类将收到与您的个人活动相同的回调。祝你好运。

PS。这是 API 级别 14 顺便说一句,所以它不适用于旧手机。

【讨论】:

  • @ClarkXP 是的,但继承链接对于应用程序类来说太强了。这还不够模块化,无法转换为库。
  • 澄清register 行:在你的回调类(有implements Application.ActivityLifecycleCallbacks)中,在它的构造函数中做getApplication().registerActivityLifecycleCallbacks(this); 如果你的类有onCreateinit 或类似的方法当实例变为活动状态时运行,将该行放在那里而不是在构造函数中(因为该类可能在完全准备好之前不希望接收回调)。
  • 这对我来说看起来很完美,但我想知道在哪里调用 unregisterActivityLifecycleCallbacks () 方法。不需要吗?
  • @Amit 这取决于监听回调的内容以及该对象的生命周期。显然,一旦该对象应该被处理掉,你就应该取消注册,否则你会通过应用程序类泄漏它。
  • 对于unregisterActivityLifecyleCallbacks,为了避免内存泄漏,我想您可以在registerActivityLifecycleCallbacks 中执行override fun onActivityDestroyed(activity: Activity?) { AppController.appInstance.registerActivityLifecycleCallbacks(this) }。但还没有自己证明。抱歉,这是 Kotlin。
【解决方案2】:

我自己实现了Application.ActivityLifecycleCallbacks。我正在使用SherlockActivity,但对于普通的 Activity 类可能会起作用。

首先,我正在创建一个接口,其中包含用于跟踪活动生命周期的所有方法:

public interface ActivityLifecycleCallbacks{
    public void onActivityStopped(Activity activity);
    public void onActivityStarted(Activity activity);
    public void onActivitySaveInstanceState(Activity activity, Bundle outState);
    public void onActivityResumed(Activity activity);
    public void onActivityPaused(Activity activity);
    public void onActivityDestroyed(Activity activity);
    public void onActivityCreated(Activity activity, Bundle savedInstanceState);
}

其次,我在我的Application类中实现了这个接口:

public class MyApplication extends Application implements my.package.ActivityLifecycleCallbacks{

    @Override
    public void onCreate() {
        super.onCreate();           
    }

    @Override
    public void onActivityStopped(Activity activity) {
        Log.i("Tracking Activity Stopped", activity.getLocalClassName());

    }

    @Override
    public void onActivityStarted(Activity activity) {
        Log.i("Tracking Activity Started", activity.getLocalClassName());

    }

    @Override
    public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        Log.i("Tracking Activity SaveInstanceState", activity.getLocalClassName());
    }

    @Override
    public void onActivityResumed(Activity activity) {
        Log.i("Tracking Activity Resumed", activity.getLocalClassName());
    }

    @Override
    public void onActivityPaused(Activity activity) {
        Log.i("Tracking Activity Paused", activity.getLocalClassName());
    }

    @Override
    public void onActivityDestroyed(Activity activity) {
        Log.i("Tracking Activity Destroyed", activity.getLocalClassName());
    }

    @Override
    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        Log.i("Tracking Activity Created", activity.getLocalClassName());
    }
}

第三,我正在创建一个从 SherlockActivity 扩展的类:

public class MySherlockActivity extends SherlockActivity {

    protected MyApplication nMyApplication;

    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        nMyApplication = (MyApplication) getApplication();
        nMyApplication.onActivityCreated(this, savedInstanceState);
    }

    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
        nMyApplication.onActivityResumed(this);
    }

    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        nMyApplication.onActivityPaused(this);
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        nMyApplication.onActivityDestroyed(this);
    }

    @Override
    protected void onStart() {
        super.onStart();
        nMyApplication.onActivityStarted(this);
    }

    @Override
    protected void onStop() {
        super.onStop();
        nMyApplication.onActivityStopped(this);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        nMyApplication.onActivitySaveInstanceState(this, outState);
    }   
}

第四,所有继承自SherlockActivity的类,我替换为MySherlockActivity:

public class MainActivity extends MySherlockActivity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

}

现在,在 logcat 中,您将看到在 MyApplication 中的接口实现中编写的日志。

更新

此实现已通过 API 级别 9(姜饼)、API 级别 12(蜂窝)和 API 级别 17(果冻豆)进行了测试,并且运行良好。可能适用于 Android 的旧版本。

【讨论】:

  • 为了完整起见,请考虑将 onActivityRestart() 添加到接口中,并将适当的方法添加到 MyApplication 和 MySherlockActivity。我意识到这个方法不是 Android 的 ActivityLifecycleCallbacks 的一部分,但 onRestart Activity 生命周期的一部分。
  • 对旧设备很有用。注意:如果您(任何人)希望使用 Application.ActivityLifecycleCallbacks,那么您假设 API 足够新,您可以省略自定义接口和 Activity 扩展。只需执行 (1) 第一个代码部分,它显示了如何扩展一个类(在本例中为 Application)来实现接口,但要执行 implements Application.ActivityLifecycleCallbacks。并且 (2) getApplication().registerActivityLifecycleCallbacks(this); 在您的回调类的构造函数或 onCreate 中。
【解决方案3】:
@Override
public void onCreate() {
    super.onCreate();
    registerActivityLifecycleCallbacks(MyApplication.this/*(Your Application Name)*/);
}

仅在 Application 类上添加这一行,一切正常。

【讨论】:

    【解决方案4】:

    试试这个:http://engineering.meetme.com/2015/04/android-determine-when-app-is-opened-or-closed/#comment-202

    它提出了一个AppForegroundStateManager,每个活动通过其onStop()onStart() 函数向其报告,如下所示:

    @Override
    protected void onStart() {
        super.onStart();
        AppForegroundStateManager.getInstance().onActivityVisible(this);
    }
    
    @Override
    protected void onStop() {
        AppForegroundStateManager.getInstance().onActivityNotVisible(this);
        super.onStop();
    }
    

    您的Application 类实现了一个这样的监听器:

    public class MyApplication extends Application {
        @Override
        public void onCreate() {
            super.onCreate();
            AppForegroundStateManager.getInstance().addListener(this);
        }
    
        @Override
        public void onAppForegroundStateChange(AppForegroundStateManager.AppForegroundState newState) {
            if (AppForegroundStateManager.AppForegroundState.IN_FOREGROUND.equals(newState)) {
                // App just entered the foreground. Do something here!
                Log.i(TAG, "App Just Entered the Foreground with launch mechanism of: " + mLaunchMechanism);
            } else {
                // App just entered the background. Set our launch mode back to the default of direct.
                mLaunchMechanism = LaunchMechanism.DIRECT;
            }
        }
    }
    

    它还包括确定应用程序打开方式的提示和技巧 - 从通知、打开应用程序的 URL 或直接从应用程序菜单。这是通过 Application 类中的 Enum 完成的:

    public enum LaunchMechanism {
        DIRECT,
        NOTIFICATION,
        URL,
        BACKGROUND
    }
    
    private LaunchMechanism mLaunchMechanism = LaunchMechanism.DIRECT;
    
    public void setLaunchMechanism(LaunchMechanism launchMechanism) {
        mLaunchMechanism = launchMechanism;
    }
    

    在我们的实现中,当我们启动一个将启动第三方 Activity 的 Activity 时,我们有一些标志,例如用户是否从我们的应用程序拨打电话或是否启动了浏览器。在启动活动的onStop() 中,我们然后进行这样的检查,以仅在这些标志为假时报告活动的不可见性:

    if(!flag_userLaunchedThirdPartyActivity){
         AppForegroundStateManager.getInstance().onActivityNotVisible(this);
         }
    

    用于检查应用程序是否进入后台 - 例如当设备的屏幕变暗或用户接到电话时 - 它的工作原理如下:

    public static boolean isApplicationGoingToBackground(final Context context) {
    
        ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<RunningTaskInfo> tasks = am.getRunningTasks(1);
        if (!tasks.isEmpty()) {
            ComponentName topActivity = tasks.get(0).topActivity;
            if (!topActivity.getPackageName().equals(context.getPackageName())) {
                setLaunchMechanism(LaunchMechanism.BACKGROUND);
                return true;
            }
        }
    
        setLaunchMechanism(LaunchMechanism.DIRECT);
        return false;
    }
    

    此解决方案不依赖于 API 级别,因此它应该一直工作到 API 级别 1。

    【讨论】:

      猜你喜欢
      • 2012-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-13
      • 2011-12-18
      • 1970-01-01
      • 2020-07-20
      相关资源
      最近更新 更多