学习Kotlin之AnkoLogger
2017-07-13 本文已影响618人
Thresh0ld
根据AnkoLogger里的理念自己写了一个Logger。主要目的还是为了学习巩固Kotlin
- 先看Logger接口
interface Logger {
val tag: String
get() {
return getTag(javaClass) //牛逼特性来了,Kotlin可以在运行时获取当前的类。javaClass这个val字段存在于每个Class(类/接口/枚举)中
}
fun isLogable(): Boolean = true
fun verbose(message: Any?){ //不建议在这里声明默认实现方法(除非继承类要重写),建议使用扩展方法,这样让接口保持清晰
if (isLogable()) {
println("[$tag][Verbose]:$message")
}
}
}
关键点我都在代码处写了出来了。
-
javaClass这个是字段,在每个类/接口/枚举中都有这个字段,这个字段能在运行时获取当前类。
-
接口可以声明val字段,var字段是不允许的(因为接口是抽象的,不能存放实例对象,他不是类)。
-
接口中可以声明默认方法,这个特性和Java8中的是一样的,接口中的默认方法在实现类中可以选择重写也可以选择不重写(因为默认实现了嘛)。
-
对于与业务有关的默认方法建议用扩展方法实现。这样能保持接口干净
-
再看下扩展方法
inline fun<reified T:Any> Logger() = Logger(T::class.java)
- 这里inline关键词在编译的时候将这个方法里的内容内联到调用的地方去,而不是跳转到这个方法里执行方法体。内联不应乱用,只应该用在方法体很小的地方,含有大量逻辑及代码的地方还应用普通方法。内联是为了提高效率,避免创建不必要的对象
- reified关键词需要和inline一起使用,因为只有内联的泛型方法才可以在运行时获取泛型类型的类型。
最后附上代码如下,里面包含关键点的注释,大家可以放到copy到IDE中run一下看看。
package com.threshold.kotlin
interface Logger {
val tag: String
get() {
return getTag(javaClass) //牛逼特性来了,Kotlin可以在运行时获取当前的类。javaClass这个val字段存在于每个Class(类/接口/枚举)中
}
fun isLogable(): Boolean = true
fun verbose(message: Any?){ //不建议在这里声明默认实现方法(除非继承类要重写),建议使用扩展方法,这样让接口保持清晰
if (isLogable()) {
println("[$tag][Verbose]:$message")
}
}
}
fun Logger(clazz: Class<*>):Logger = object : Logger {
override val tag: String
get() = getTag(clazz)
}
inline fun<reified T:Any> Logger() = Logger(T::class.java)
/*
复习下: inline 内联,可以提高程序执行效率,避免创建许多中间对象。
reified 使具体化(翻译来的) 他必须和inline一起使用(不能inline的方法里传递的泛型对象是不能具体化的)
还有点要注意,Kotlin的泛型方法中的尖括号必须紧跟着fun关键字后面,不能跟在方法名后面,
熟悉C#或许会感觉很别扭,但是这个跟Java是一脉相连的,java要求的是在方法名之前要声明泛型。
fun testGeneric<T:Any>(){
//编译错误.泛型必须紧跟着fun关键字后面。上面这种写法像是在使用的时候
}
*/
fun Logger.debug(message: Any?) {
if (isLogable()) {
println("[$tag][Debug]:$message")
}
}
inline fun Logger.debug(message: () -> Any?){
if (isLogable()) {
println("[$tag][Debug]:${message()}")
}
}
private fun getTag(clazz: Class<*>):String {
val tag = clazz.simpleName
return if (tag.length < 23) {
tag
} else {
tag.subSequence(0,23).toString()
}
}
class LoggerTest1:Logger{
override val tag: String
get() = "MyTag"
override fun isLogable(): Boolean {
return super.isLogable() //在Android中一般是根据Build中的Debug字段来判断是否需要输出日志
}
fun doSomething(){
debug("Do something")
verbose("log something too")
}
}
class LogggrTest2{
val logger = Logger(LogggrTest2::class.java)
//注意这里的Logger(xx)其实是顶部方法,只不过他的方法名就是这个接口名。这个方法使用object关键词生成了一个匿名对象。注意他不是构造函数。
fun doSomething(){
logger.verbose("verbose something")
logger.debug {
"lazy debug string"+ 2 //This is only calculate when logable is true
}
}
}
class LoggerTest3{
val logger = Logger<LoggerTest3>()
fun doSomething(){
logger.verbose("verbose logger something")
logger.debug {
"lazy debug message"
}
logger.debug("normal debug message")
}
}
fun main(args:Array<String>): Unit {
val loggerTest1 = LoggerTest1()
loggerTest1.doSomething()
val loggerTest2 = LogggrTest2()
loggerTest2.doSomething()
val loggerTest3 = LoggerTest3()
loggerTest3.doSomething()
}
运行结果:
[MyTag][Debug]:Do something
[MyTag][Verbose]:log something too
[LogggrTest2][Verbose]:verbose something
[LogggrTest2][Debug]:lazy debug string2
[LoggerTest3][Verbose]:verbose logger something
[LoggerTest3][Debug]:lazy debug message
[LoggerTest3][Debug]:normal debug message
Process finished with exit code 0
![](https://img.haomeiwen.com/i1428538/27b8b23065ed36aa.jpg)