Automatically Log Android Lifecycle Events Using Activitylifecyclecallbacks

Automatically log Android lifecycle events using ActivityLifecycleCallbacks?

I did my own implementation of Application.ActivityLifecycleCallbacks. I'm using SherlockActivity, but for normal Activity class might work.

First, I'm creating an interface that have all methods for track the activities lifecycle:

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

Second, I implemented this interface in my Application's class:

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

Third, I'm creating a class that extends from 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);
}
}

Fourth, all class that extend from SherlockActivity, I replaced for MySherlockActivity:

public class MainActivity extends MySherlockActivity{

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

}

Now, in the logcat you will see the logs programmed in the Interface implementation made in MyApplication.

UPDATE

This implementation was tested from API Level 9 (Gingerbread), API Level 12 (Honeycomb) and API Level 17 (Jelly Bean) and works fine. Might works in Android's older versions.

Monitoring android lifecycle events from a library

I think that your best (long term) option is to have a setup along with the integration of the library (i.e. pass the Application in an entry point of your library).

That said, there is an undocumented way to get the current Application. as described here: https://stackoverflow.com/a/12495865/458365

try {
final Class<?> activityThreadClass =
Class.forName("android.app.ActivityThread");
final Method method =
activityThreadClass.getMethod("currentApplication");
return (Application) method.invoke(null, (Object[]) null);
} catch (final Exception e) {
// handle exception
}

Once you have that you can call Application.registerActivityLifecycleCallbacks() to register your own ActivityLifecycleCallbacks

Update:
Another alternative to get the application (Context) that I've come across is to use a Content provider. I think libraries like Firebase use this method because it has zero set up. However, it requires the consumer of the library to have an application object (which actually is the same as with the manual method) but it does look a lot cleaner:

Inside the onCreate of the CP we can cast getContext as Application and go from there with the Callbacks process.

Source: https://medium.com/@andretietz/auto-initialize-your-android-library-2349daf06920

Are Android.App.Application activity life cycle callbacks invoked on the UI thread?

You can easily check what thread called the method:

  1. Via logging Thread.currentThread().getName(), in case of Main thread you'll see something like Main Thread.
  2. Via checking the Looper of current thread Looper.getMainLooper() == Looper.getMyLooper(), it'll be true in case of Main thread.
  3. Via putting a break point to the method and checking thread name in the stacktrace in your IDE/debugger.

Registering for an activity's events

One way to get events from the lifecycle of other activities is to register your class as an Application.ActivityLifecycleCallbacks with the main Application instance and filter events for the Activity you're interested in.

This is a short example (you may want to register the callbacks from another method/class other than MainActivity.onCreate or you'll miss that message ;) and you may have a dependency there that you don't want)

On the activity you want to spy:

public class MainActivity extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

// Register a spy for this activity
getApplication().registerActivityLifecycleCallbacks(new ActivitySpy(this));
}
}

Then the Spy code looks something like:

public class ActivitySpy implements ActivityLifecycleCallbacks {

private final Activity mActivity;

public ActivitySpy(Activity activity) {
mActivity = activity;
}

@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
if (mActivity == activity)
Log.i("SPY", "Activity Created");
}

@Override
public void onActivityDestroyed(Activity activity) {
if (mActivity == activity)
Log.i("SPY", "Activity Destroyed");
}

// (...) Other overrides

}

You can also register the spy from another place if you have a reference to the Activity you want to follow.

I hope this helps :)

EDIT: I forgot to mention, this will only work on API Level 14 and above...

Hooking into fragment's lifecycle like Application.ActivityLifecycleCallbacks

Since version 25.2.0 of Android support library, the class FragmentManager.FragmentLifecycleCallbacks is static and accessible to all.

We can now use an instance of that class and register it in the supportFragmentManager of the Activity.

public class ExampleActivity extends AppCompatActivity {

public void onCreate(Bundle savedInstaceState) {

// initialization code
getSupportFragmentManager()
.registerFragmentLifecycleCallbacks(new FragmentManager.FragmentLifecycleCallbacks() {
@Override
public void onFragmentPreAttached(FragmentManager fm, Fragment f, Context context) {
super.onFragmentPreAttached(fm, f, context);
}

@Override
public void onFragmentAttached(FragmentManager fm, Fragment f, Context context) {
super.onFragmentAttached(fm, f, context);
}

@Override
public void onFragmentCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {
super.onFragmentCreated(fm, f, savedInstanceState);
}

@Override
public void onFragmentActivityCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {
super.onFragmentActivityCreated(fm, f, savedInstanceState);
}

@Override
public void onFragmentViewCreated(FragmentManager fm, Fragment f, View v, Bundle savedInstanceState) {
super.onFragmentViewCreated(fm, f, v, savedInstanceState);
}

@Override
public void onFragmentStarted(FragmentManager fm, Fragment f) {
super.onFragmentStarted(fm, f);
}

@Override
public void onFragmentResumed(FragmentManager fm, Fragment f) {
super.onFragmentResumed(fm, f);
}

@Override
public void onFragmentPaused(FragmentManager fm, Fragment f) {
super.onFragmentPaused(fm, f);
}

@Override
public void onFragmentStopped(FragmentManager fm, Fragment f) {
super.onFragmentStopped(fm, f);
}

@Override
public void onFragmentSaveInstanceState(FragmentManager fm, Fragment f, Bundle outState) {
super.onFragmentSaveInstanceState(fm, f, outState);
}

@Override
public void onFragmentViewDestroyed(FragmentManager fm, Fragment f) {
super.onFragmentViewDestroyed(fm, f);
}

@Override
public void onFragmentDestroyed(FragmentManager fm, Fragment f) {
super.onFragmentDestroyed(fm, f);
}

@Override
public void onFragmentDetached(FragmentManager fm, Fragment f) {
super.onFragmentDetached(fm, f);
}
}, true);
}
}

What are the Android application lifecycle methods? (not activity life cycle methods.)

This happens because of the Activity LifeCycle. When you close your app by pressing the home button, the onStop() method of the respective Activity which was active at the time is called upon. This method does not destroy the Activity completely, it only stops it.

The Activities in the Android OS are destroyed by calling onDestroy() method of the respective Activity. However, onDestroy() method cannot be called directly because it is a method of Activity's LifeCycle. It gets called automatically by the Android OS. To ensure that Activity's onDestroy() method gets called as soon as your Activity stops, we will call finish() method inside the onStop() method of your respective Activity(s).

@Override
protected void onStop() {
super.onStop();
finish();
}

Now, when you'll start your app again, it will start from the beginning i.e. the splash screen.



Related Topics



Leave a reply



Submit