Search code examples
androidloggingandroid-lifecycleactivity-lifecycletimber-android

Why Timber log produces the log messages twice once the activity restart its lifecycle in Android?


During the development of my Android project, I encountered the encouraged use of the Timber log library; but when I switched to using it, I found that once the activity in which I place Timber.plant(new Timber.DebugTree()); restarts its lifecycle (calling onCreate(savedInstanceState) a second time), all the log generated by Timber get produced twice in the LogCat panel.

This simple code illustrates the problem:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "StateChange";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        Timber.plant(new Timber.DebugTree());   // plant a debug tree
        
        setContentView(ActivityMainBinding.inflate(getLayoutInflater()).getRoot());

        Timber.tag(TAG).i("onCreate");  // using timber log
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.i(TAG, "onDestroy");    // using android log
    }
}

Now when I run the app and rotate the screen (which will cause the activity to destroy and recreate again), the content of the LogCat is as follow:

... I/StateChange: onCreate     <-- everything is normal in the first creation
... I/StateChange: onDestroy    
... I/StateChange: onCreate     <-- when lifecycle restarts (rotate screen)
... I/StateChange: onCreate     <-- those use Timber will get logged twice
... I/StateChange: onDestroy    <-- but those use standard log remain normal
... I/StateChange: onCreate     <-- rotate again
... I/StateChange: onCreate     <-- same problem, but only twice

So anyway this is still my first use of Timber, I don't know if we should put any code anywhere to handle the situation. Although this seems harmless enough, the project I am currently doing involves a lot of debugging from the LogCat panel, and looking at twice as much information to debug the app is really cumbersome.


Solution

  • This is the expected behaviour. After all, you are planting a new "Debug tree" every time the activity gets created.

    Instead of doing it this way, you should have a Custom Application class and override the onCreate function. Inside, just plant the "Debug tree".

    E.g.:

    public class MyCustomApplication extends Application {
    
        @Override
        public void onCreate() {
            super.onCreate();
            Timber.plant(new Timber.DebugTree());
            ...
    }
    

    This way, the Timber debug tree will only be "planted" on app initialisation.