为什么 activity 在 Android 重新启动其生命周期后,Timber 日志会生成两次日志消息?

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

在我的 Android 项目开发过程中,我遇到了鼓励使用 Timber 日志库的情况;但是当我切换到使用它时,我发现一旦我放置 Timber.plant(new Timber.DebugTree()); 的 activity 重新启动它的生命周期(第二次调用 onCreate(savedInstanceState) ),Timber 生成的所有日志都会生成在 LogCat 面板中两次。

这个简单的代码说明了问题:

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

现在当我运行应用程序旋转屏幕时(这会导致activity销毁并重新创建),LogCat的内容如下:

... 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

所以无论如何这仍然是我第一次使用 Timber,我不知道我们是否应该在任何地方放置任何代码来处理这种情况。虽然这看起来无伤大雅,但我现在做的项目涉及到很多LogCat面板的调试,查看两倍的信息来调试应用程序真的很麻烦。

您应该在应用程序 onCreate() 方法中种植木材,而不是 Activity onCreate() 方法。 否则,您可以将 Timber.plant() 方法包装成这样的条件:

if (Timber.treeCount() == 0) {
    Timber.plant(new Timber.DebugTree());   // plant a debug tree
}

这是预期的行为。毕竟,每次创建 activity 时,您都会种植一棵新的“调试树”。

您应该有一个自定义 Application class 并覆盖 onCreate 函数,而不是这样做。在里面,只需种植“调试树”即可。

例如:

public class MyCustomApplication extends Application {

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

这样,Timber 调试树只会在应用程序初始化时被“种植”。