1

这不是重复。“对象”表达式是关键字。

我正在尝试将 Timber Android 库与https://github.com/orhanobut/logger集成,我需要一个 customLogStrategyForTimber 来满足我的需要。

我想出了这个逻辑。但是我在初始化时遇到了困难customLogStrategyForTimber

class App : Application() {
    // I CREATED THE lateinit VARIABLE
    lateinit var customLogStrategyForTimber: LogStrategy
    
    override fun onCreate() {
        super.onCreate()
        Timber.plant(object : Timber.DebugTree() {
            override fun log(
                priorityTimber: Int, tagTimber: String?, message: String, t: Throwable?
            ) {
                
                // USED THE lateinit HERE
                customLogStrategyForTimber = object : LogcatLogStrategy() {
                    override fun log(priority: Int, tag: String?, message: String) {
                        super.log(priorityTimber, tagTimber, message)
                    }
                }

 println("customLogStrategyForTimber: ${::customLogStrategyForTimber.isInitialized}") // PRINTS TRUE
            }
        })

        println("customLogStrategyForTimber OUTSIDE: ${::customLogStrategyForTimber.isInitialized}") // PRINTS FALSE - WHY??


            var formatStrategy1 = PrettyFormatStrategy.newBuilder()
                
                // TRYING TO CALL THE lateinit VARIABLE HERE
                // NOW, HERE THE lateinit IS NOT INITIALIZED.
                .logStrategy(customLogStrategyForTimber)
                .build()
            Logger.addLogAdapter(AndroidLogAdapter(formatStrategy1))
    }
}

customLogStrategyForTimber永远不会初始化。有没有更好的方法来做这个逻辑?尝试formatStrategy在第一个覆盖有趣的日志方法中添加整个代码会导致使用 Timber 日志记录时出现意外行为,因此这似乎不是一个简单的选择。

运行应用程序时崩溃

  Caused by: kotlin.UninitializedPropertyAccessException: lateinit property customLogStrategyForTimber has not been initialized

也试过使用isInitialized

它里面的代码永远不会运行。

编辑:

创建了一个示例项目:https ://github.com/shipsywor/demotimberlogger

编辑2:

println在上面的代码中添加了语句。您将看到::customLogStrategyForTimber.isInitialized在代码的一个点返回 False,在另一个点返回 True

注意:我不能将 formatStrategy 代码放在 Timber.plant {...} 中。它会导致意外行为。

4

4 回答 4

1

看起来您不必要地创建了一个本地 val customLogStrategyForTimber,它只能在Timber.plant()方法中访问。实际上,您并没有真正使用您在班级顶部声明的 lateinit var。如果您刚刚val从方法内的对象声明中删除Timber.plant(),您的代码将按您的预期工作。

就像现在一样,您声明的对象保留在Timber.plant()方法内部,并且无法在外部访问。

于 2021-06-15T08:01:31.983 回答
1

让我给你解释一下。Timber.plant 是一个需要一些时间才能完成工作的线程。您在日志中出现错误的代码突然在 Timber.plan 之后运行并打印错误,同时 Timper.plan 线程正在执行并行和初始化变量,然后在您得到正确的地方打印。

你应该这样做:

     class App : Application() {
 
    lateinit var customLogStrategyForTimber: LogStrategy
 
    override fun onCreate() {
        super.onCreate()
 
        Timber.plant(object : Timber.DebugTree() {
 
            override fun log(
                priorityTimber: Int, tagTimber: String?, message: String, t: Throwable?
            ) {
                customLogStrategyForTimber = object : LogcatLogStrategy() {
                    override fun log(priority: Int, tag: String?, message: String) {
                        super.log(priorityTimber, "global_tag_$tagTimber", message)
                    }
                }
                    Logger.d(message)
            }
        })
 
 
        thread {
            val formatStrategy: FormatStrategy = PrettyFormatStrategy.newBuilder()
                .showThreadInfo(false)
                .methodCount(1)
                .methodOffset(5)
                .logStrategy(customLogStrategyForTimber)
                .build()
 
            Logger.addLogAdapter(AndroidLogAdapter(formatStrategy))
 
            println("global_tag INSIDE thread: ${::customLogStrategyForTimber.isInitialized}")
 
        }
 
        Timber.d("Initialize Timber")
    }
}
于 2021-06-15T08:03:00.933 回答
1

您初始化的代码在您当场创建的实现lateinit varlog()DebugTree在此处调用时不会执行它Timber.plant(),您只是在注册一个DebugTree具有某些实现的实例。

println因此,当您使用“OUTSIDE”到达时,该log方法从未被调用过,因此customLogStrategyForTimber尚未初始化。

于 2021-06-15T08:59:11.007 回答
0

根据您对其他答案的评论,我想我了解您要做什么。

如果您有一个 LogcatLogStrategy 的具体实现,您可以在其中设置属性,那么看起来这将是不那么脆弱的代码。

class MyLogcatLogStrategy: LogcatLogStrategy() {

    var timberTag: String? = null
    var timberPriority: Int = -1

    override fun log(priority: Int, tag: String?, message: String) {
        super.log(timberPriority, timberTag, message)
    }
}

然后,您可以拥有一个实例,并且可以从任何地方安全地更新它。

class App : Application() {
    val customLogStrategyForTimber = MyLogcatLogStrategy()
    
    override fun onCreate() {
        super.onCreate()
        Timber.plant(object : Timber.DebugTree() {
            override fun log(
                priority: Int, tag: String?, message: String, t: Throwable?
            ) {
                  customLogStrategyForTimber.apply {
                      timberTag = tag
                      timberPriority = priority
                  }
            }
        }
        val formatStrategy1 = PrettyFormatStrategy.newBuilder()
            .logStrategy(customLogStrategyForTimber)
            .build()
        Logger.addLogAdapter(AndroidLogAdapter(formatStrategy1))
    }
}

我不知道这是否会在正确的线程上更新您的标签值,或者以正确的顺序更新标签以正确显示在您的日志中。

完全消除 Timber 并将其确定标记的方法从其源代码复制到您的 LogcatLogStrategy 中可能会更容易,但我不熟悉您正在使用的其他日志库。也许是这样的:

class MyLogcatLogStrategy: LogcatLogStrategy() {
    private val ignoredClassNames = listOf(
        MyLogcatLogStrategy::class.java.name,
        /* The names of all the classes in your logging library */
    )

    //Adapted from Timber:
    private val tag: String?
      get() = Throwable().stackTrace
          .first { it.className !in ignoredClassNames }
          .let(::createStackElementTag)

    override fun log(priority: Int, ignoredTag: String?, message: String) {
        super.log(priority, this.tag, message)
    }

    // From Timber: (https://github.com/JakeWharton/timber/blob/master/timber/src/main/java/timber/log/Timber.kt#L216)
    private fun createStackElementTag(element: StackTraceElement): String? {
      var tag = element.className.substringAfterLast('.')
      val m = ANONYMOUS_CLASS.matcher(tag)
      if (m.find()) {
        tag = m.replaceAll("")
      }
      // Tag length limit was removed in API 24.
      return if (tag.length <= MAX_TAG_LENGTH || Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        tag
      } else {
        tag.substring(0, MAX_TAG_LENGTH)
      }
    }

    companion object {
      private val ANONYMOUS_CLASS = Pattern.compile("(\\$\\d+)+$")
    }
}
于 2021-06-15T13:16:40.583 回答