Android Kotlin 开发需知

Android Kotlin 开发需知_第1张图片

变量 延迟加载

// 某些成员变量在声明时无法初始化,且不想使用可空类型(也就是带?的类型)。可使用 lateinit 和 by lazy

    // 不知道具体值,后面再赋值使用;所以必须var
    lateinit var name: String

    // 知道具体值,用到的时候再加载,表示不可变的值,所以必须val
    //  {}中的最后一行代码返回初始化的结果,加载时机为第一次调用常量的时候,且只会加载一次
    private val book by lazy {
        LogUtil.i("这行代码不会影响book赋值")
        "Android"
    }

 访问权限修饰符

    public:      公开,可见性最大,哪里可以引用  Kotlin 的类默认是 public 的
    private:     私有,可见性最小,根据声明位置不同可分为类中可见和文件中可见
    protected:   保护,相当于private+ , 子类可见
    internal:    内部,仅对module内可见,(A module修饰,B module无法访问)

构造方法,init代码块

/**
 * 构造函数单独用了一个 constructor 关键字来和其他的 fun 做区分,分主构造和次构造
 * 如果类中有主构造器,所有次构造器都需要通过this关键字调用主构造器
 *
 * 从主构造器的特性出发,一旦在类中声明了主构造器,就包含两点:
 *     必须性:创建类的对象时,不管使用哪个构造器,都需要主构造器的参与
 *     第一性:在类的初始化过程中,首先执行的就是主构造器
 */
class User constructor(var name: String) {

    // init代码块紧跟主构造器之后,因为主构造函数没有代码体,init代码块可充当主构造器代码体的功能;  init代码块优先于次构造器执行的。
    init {
        // 如果把主构造器看成身体的头部,那么 init 代码块就是颈部,次构造器就相当于身体其余部分
    }

    // 直接调用主构造器
    constructor(name: String, age: Int) : this(name)

    // 通过上一个次构造函数,间接调用主构造器
    constructor(name: String, age: Int, id: Int) : this(name, age) {}
    
}

 constructor 关键字省略,私有,参数

// 主构造器中 constructor 关键字如果没有被 可见性修饰符 或 注释 标注可以省略
class User(var name: String) {
    constructor(name: String, age: Int) : this(name)
}

// 主构造器被修饰为私有的,外部就无法调用该构造器
class User private constructor(var name: String) {
}
// 主构造函数里面声明属性,前面加 var / val 构造参数同时成为成员变量
class User(var name: String) {
}

// ↑↓ 上下等价  
class User(name: String) {
    var name: String = name
}

静态方法

一共三种实现方式:①object ②伴生对象 ③顶层函数

/**
 * Kotlin的object首字母小写,Java的Object在Kotlin中不用了,Java的Object在Kotlin中变成了Any
 * 在 Kotlin 中object不是类属于关键字
 *
 * 用object声明一个类时,表明这个类是一个单例类,可继承其他类,可以定义在全局也可以在类的内部使用
 * object声明不能用在方法和inner内部类中,但是能嵌套在其他object声明和嵌套类中
 * object 定义后即刻实例化,因此 object 不能有定义构造函数
 */
object SystemUtil{
}


/**
 * 用 object 修饰的对象中的变量和函数都是静态的,但有时候只想让类中的一部分函数和变量是静态的
 * 和 object 不同, companion object 的定义完全属于类的本身,
 * 因此 companion object 不能脱离类而定义在全局之中。
 * 类似 Java 里的 static 变量
 */
class ScreenUtil {

    /*
     * companion object 修饰为伴生对象,伴生对象在类中只能存在一个
     * Java 中的静态变量和方法,在 Kotlin 中都放在了 companion object 中。
     * 因此 Java 中的静态初始化在 Kotlin 中自然也是放在  companion object 中的,
     * 像类的初始化代码一样,由 init 和一对大括号表示
     */
    companion object {

        // 静态初始化
        init { }

    }

}

真实项目中推荐的写法是使用伴生对象和 object 关键字结合的方式,示例如下:

class UmengEventUtil {

    companion object {
        @JvmStatic
        fun getInstance(): UmengEventUtil {
            return Holder.instance
        }
    }

    private object Holder {
        val instance = UmengEventUtil()
    }

    fun onRegister(mContext: Context) {
        MobclickAgent.onEvent(mContext, "__cust_event_1")
    }
    
}

顶层声明 top - level property / function

又称顶层函数,直接在文件中定义函数和属性,这种顶层函数不要声明在module内最顶层的包中,至少要在一个包中

/*
顶层声明属于 package,不在 class/object 内
属性和函数,不属于任何 class,而是直接属于 package
它和静态变量、静态函数一样是全局的,用起来更方便:在其它地方用的时候,类名都不用写
*/

fun stringToDouble(money: String): Double {
    return money.toDouble()
}

get,set 方法

// 默认kotlin已自动生产set,get方法,可省略
class User() {
     var name: String? = null
        set(value) {
            field = value
        }
        get() = field
}

// 上下等价   ↑↓
class User{
     var name: String? = null
}
// 如只想让外部使用,不想外部set,可在set前面添加private将set方法私有化
class User {
    var name: String
        private set
    
    init {
        name = "设置name值,外部只能调用get方法"
    }
}

数据类

相比JavaBean手动生成各种方法,kotlin data class要简单很多

/**
 *  var user = User("zs",18,"10001")
 * 自动生成
 * toString()       LogUtil.e("user.toString = $user")
 * copy()           var user2 = user.copy(id = 2)
 * equals()         user.equals(user2) 输出 true
 * hashCode()       user.hashCode 输出内存地址
 * componentN()     解构声明   val (name, age, code) = User("zs", 0, "1001")
 */
data class User(
    var name: String,
    var age: Int,
    var code: String
)

扩展函数

// 原本使用
fun dp2px(dp: Float): Float {
    return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().displayMetrics)
}

dp2px(3.4f)

// 扩展函数
fun Float.dp2px(): Float {
    return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this, Resources.getSystem().displayMetrics)
}

3.2f.dp2px()

let关键字

        // 使用let之前
        tvName.text = user?.name
        tvAge.text = user?.age
        tvCode.text = user?.code

        // let 配合可空性 “?”使用,如果user为 null 不执行 let 内部代码,如果有返回值返回null,在 let 中 it 表示引用对象
        user?.let {
            tvName.text = it.name
            tvAge.text = it.age
            tvCode.text = it.code
        }

with函数

        val user = User()
        tvName.text = user.name
        tvAge.text = user.age
        tvCode.text = user.code

        // with 函数适用于对同一个对象执行多次操作
        with(user) {
            tvName.text = name
            tvAge.text = age
            tvCode.text = code
        }

        // with 函数最后一行为返回值
        val nickName = with(user) {
            name
        }


        // 适用于同一个类多个方法省去类名重复,直接调用类中方法或属性,在RecyclerView绑定数据时经常使用

run函数

        /*
        run函数是let、with两个函数结合体,
        它弥补了let函数在函数体内必须使用it参数替代对象,
        在run函数中可以像with函数一样,直接访问实例的公有属性和方法
        另一方面它弥补了with函数传入对象判空问题,在run函数中可以像let函数一样做判空处理
         */
        user?.run {
            tvName.text = name
            tvAge.text = age
            tvCode.text = code
        }

        // 适用于let、with函数任何场景

apply函数

    // 使用方式和run一致,但是不同的是:最后一行不作为返回值,apply函数的返回值是本身,在函数内部可任意调用对象属性和方法,甚至给属性赋值等
    val fragmentList = ArrayList().apply {
        add(HomeFragment.newInstance())
        add(OrderFragment.newInstance())
        add(UserFragment.newInstance())
    }

enum 枚举

// 1:枚举最常用的方法:定义枚举常量,使用逗号隔开,每个枚举常量都是一个对象 
enum class Color {
    RED,
    GREEN,
    BLUE
}

// 2:定义枚举常量时,为其声明一个成员变量,可以为其初始化一个值
enum class Color(val rgb: Int) {
    RED(0xFF0000),
    GREEN(0x00FF00),
    BLUE(0x0000FF)
}

 

Android Kotlin 开发需知_第2张图片 Android Kotlin 开发需知_第3张图片

你可能感兴趣的:(android,kotlin)