Kotlin快速入门

前言

记录自第一行代码第三版

变量

package 变量

fun main(){
    val a=10;
    println(a);
}

函数

package 函数

import kotlin.math.max
/*
不同文件中不能定义相同名称的函数,否则报错
 */
fun main(){
    val a=37
    val b=40
    val value= largerNumber(a, b)//返回的最大值传给value变量
    println(value)
}
//fun 函数.largerNumber(num1:Int,num2:Int): Int{
//    return max(num1,num2)
//
//}
//fun 函数.largerNumber(num1:Int,num2:Int): Int= max(num1,num2)//等号表达返回值
fun largerNumber(num1:Int,num2:Int)= max(num1,num2)//等号表达返回值


package 函数

import java.lang.Integer.max

// 函数.largerNumber(num1:Int, num2: Int):Int{
//    return max(num1,num2)
//}

循环语句

package 循环语句

//fun main(){
//    for (i in 0..10){//定义变量i,在0到10之间得区间
//
//
//    println(i)k
//
//    }
//}
//______________________________
//val  range = 0 until 10//[0,10)
//fun main() {
//    for (i in 0 until 10)//从0到9,每次都加1,相当于i++
//        println(i)
//}
//————————————————————————————————
//fun main() {
//    for (i in 0 until 10 step 2)//从0到9,每次都加2,相当于i=i+2
//        println(i)
//}
//__________________________________________
//创建降序的区间
fun main(){
    for (i in 10 downTo 1){//[10,1]
        println(i)
    }

}

程序的逻辑控制

if语句

package 程序的逻辑控制

import 函数.largerNumber

fun largerNumber2(num1:Int,num2:Int):Int{
    var value=0
    if (num1>num2){
        value=num1
    }else{
        value=num2
    }
    return value
}
//——————————————————————————————————————————————————————————————————
//if判断可以有返回值
fun largerNumber3(num1:Int,num2: Int):Int{
    val value= if (num1>num2){//将返回值给value
        num1//返回值
    }else{//将返回值给value
        num2//返回值
    }
    return value
}
//直接返回比较的结果
fun largerNumber4(num1:Int,num2: Int):Int{
     return if (num1>num2){
         num1
    }else{//将返回值给value
        num2//返回值
    }
}
//用语法糖进行精简
fun largerNumber5(num1:Int,num2: Int)=if (num1>num2){
    num1
}else{
    num2
}
//最精简版
fun largerNumber6(num1: Int,num2: Int)=if (num1>num2) num1 else num2

 //——————————————————————————————————————————————————————————————
//主程序,进行调用函数
fun main(){
    val a=37
    val b=40
    val value= largerNumber6(a, b)//返回的最大值传给value变量
    println(value)
}

when语句

package 程序的逻辑控制

fun getScore(name:String)=if (name=="Tom"){
    86
}else if (name=="jim"){
    77
}else if (name =="jack"){
    95
} else if (name == "Lily"){
    100
}else{
    0
}
//简化版
fun getScore1(name:String)=when(name){
    "Tom"->86
    "jim"->77
    "jack"->95
    "Lily"->100
    else ->0

}
//____________________________________________
//类型匹配
fun checkNumber(num:Number){
    when(num){
        is Int -> println("number is Int")
        is Double -> println("number is Double")
        else -> println("number not support")
    }
}
fun main(){
    val num1=10
    val num=10L
    checkNumber(num1)
    checkNumber(num)
}
//不带参数
fun getScore2(name:String)=when{
    name=="Tom"->86
    name=="jim"->77
    name== "jack"->95
    name=="Lily"->100
    else ->0
}
//名称以Tom开头的得86分
fun getScore3(name:String)=when{
name.startsWith("Tom")->86
    name=="jim"->77
    name== "jack"->95
    name=="Lily"->100
    else ->0
}

类与对象

package 类与对象

class Person {
    val p = Person()//调用类的构造函数,对类进行实例化,创建对象
    var name =""
    var age = 0

    fun eat(){
        println(name + "is eating.he is "+age +"years old")
    }
    fun main(){//在主函数中定义对象的属性
        p.name="jack"
        p.age=19
        p.eat()//调用对象的eat方法

    }
}

继承与构造函数

Student

package 继承与构造函数

import 类与对象.Person

class Student : Person1(){//Student类继承Person类
var sno=""
    var grade=0

}
open class Person1 {//加上open修饰符让类可以被继承
val p = Person()//调用类的构造函数,对类进行实例化,创建对象
    var name = ""
    var age = 0

    fun eat1() {
        println(name + "is eating.he is " + age + "years old")
    }
}
//无参student的实例化
val student = Student()
//open class Person1(var name:String,val age:Int){
//
//}
//——————————————————————————————————————————————————————————————
//不带参数的主构造函数
class Student1 (val sno:String,val grade:Int):Person1(){//主构造函数继承Person1类;Person1()代表子类构造函数必须调用父类中的无参构造函数
val student = Student1("a123",5)//将学号和年纪这两个字段都放到了主构造函数当中,这就表明在对Student类进行实例化的时候,必须传入
    //构造函数中要求的所有参数,指定Student1类的对象student的学号是a123,年级是5
    init {//在大括号中编写逻辑
        println("sno is"+sno)
        println("grade is "+grade)
    }

}
//两个参数的student类的实例化
val student1 = Student1("jack",19)

Student2

package 继承与构造函数

import 类与对象.Person

//有参数的构造函数
//子类定义name与age字段来接收父类的name与age
class Student2 (val sno:String,val grade: Int,name: String,age:Int):Person2(name,age){//主构造函数继承Person2类;Person2(name,age)代表子类构造函数必须调用父类中的有参构造函数
val student2 = Student2("a123",5,"jack",19)//将学号和年纪和姓名和年龄这两个字段都放到了主构造函数当中,这就表明在对Student类进行实例化的时候,必须传入
    //构造函数中要求的所有参数,指定Student1类的对象student的学号是a123,年级是5
    init {//在大括号中编写逻辑
        println("sno is"+sno)
        println("grade is "+grade)
    }

}
open class Person2( name: String, age: Int) {//定义name与age的有参函数,父类的有参构造函数
    //加上open修饰符让类可以被继承
    val p = Person2("xiaoming",15)//调用类的构造函数,对类进行实例化,创建对象
}

Student3

package 继承与构造函数
/*
次构造函数
一个类中只有有一个主构造函数,能有多个次构造函数,次构造函数也能进行实例化类
注意变量名和方法名一定要写对,不要重复
 */
class Student3(val sno:String,val grade:Int,name:String,age:Int):Person3(name,age){//主构造函数
    constructor(name: String,age: Int):this("",0,name,age){//第一个次构造函数,接收name与age参数,通过this调用主构造函数对sno与
    //grade进行赋值成初始值

    }
    constructor():this("",0){//第二个次构造函数不接收任何参数,通过this调用第一个次构造函数,页将sno与grade进行赋值成初始值

    }
}

open class Person3( name: String, age: Int) {//定义name与age的有参函数,父类的有参构造函数
//加上open修饰符让类可以被继承
val p = Person3("xiaoming",15)//调用类的构造函数,对类进行实例化,创建对象
}
//四个参数student类的实例化
val student3 =Student3("a123",5,"jack",19)

Student

package 继承与构造函数
//只有定义次构造函数,没有定义主构造函数;没有主构造函数就不用在继承的时候家Person的参数
//Person的参数是为了与主构造函数的参数相耦合
import 类与对象.Person

class Student4:Person4{
    constructor(name:String,age:Int):super(name,age){//次构造函数,直接调用父类的构造函数,所以用super关键字

    }
}
open class Person4( name: String, age: Int) {//定义name与age的有参函数,父类的有参构造函数
//加上open修饰符让类可以被继承
val p = Person2("xiaoming",15)//调用类的构造函数,对类进行实例化,创建对象
}

接口

package 接口
/*
子类继承父类,子类的变量名要和父类的变量名一致
接口中如果有()是为了调用构造函数
 */
import 类与对象.Person
import 继承与构造函数.Person2

interface Study {
    fun readBooks()//调用readBooks方法
    fun doHomework(){//调用doHomework方法
        println("do homework default implementation.")//默认实现,如果没有重写,默认执行这个代码
    }
}
class Student(private val name5:String, age5:Int):Person5(name5,age5), Study{//创建Student类来继承Person5类同时实现Study接口
    override fun readBooks() {//重写readBooks方法
        println(name5+" is reading")//输出Student的参数name5

    }

//    override fun doHomework() {//重写doHomework方法
//        println(name5+" is doing homework")//输出Student的参数name5
//
//    }
}
open class Person5( name5: String, age5: Int) {//定义name与age的有参函数,父类的有参构造函数
//加上open修饰符让类可以被继承

}

fun main() {//主函数
    val student = Student("jack",19)//创建并实例化对象
    doStudy(student)//调用doStudy方法,将实例化的对象参数传入
}

fun doStudy(study: Study) {//创建doStudy方法,创建study对象,实现Study接口
    study.readBooks()//对象调用Study接口中的readBooks方法
    study.doHomework()//对象调用Study接口中的doHomework方法
}

数据类与单例类

:是强行指定它是什么类型的
比如val str:String //强行指定str常量是String 类型

package 数据类与单例类
//数据类
class Cellphone {

    data class Cellphone1 (val brand:String,val price:Double)//创建数据类,声明手机的品牌和价格的字段
   // class Cellphone1 (val brand:String,val price:Double)//没有data修饰是输出它的地址,因为没有重写toString方法,而且不能创建对象

}
class li

fun main() {//主函数

    val cellphone1= Cellphone.Cellphone1("Samsung", 1299.99)//两个参数的数据类要用类名来指定,创建数据类的对象
    val  cellphone2= Cellphone.Cellphone1("Samsung", 1299.99)//两个参数的数据类要用类名来指定,创建数据类的对象
    println(cellphone1)//输出数据类的对象
    println("cellphone1 equals cellphone2"+(cellphone1==cellphone2))//判断两个数据类的对象是否一致

}
package 数据类与单例类
//创建单例
object Singleton {
    fun singletonTest(){//创建单例的方法
        println("singletonTest is called.")
    }
}

fun main() {
    Singleton.singletonTest()//用静态方法的方式,用类名调用单例方法来进行调用
}

集合

list

package Lambda
//集合的创建与遍历
//定义集合和添加集合中的元素要在主函数中进行
//kotlin语法与java有相似的地方,可以对比着看
class list {


}

fun main() {
    //最原始的写法
    var list=ArrayList<String>()
    list.add("Apple")
    list.add("Banana")
    list.add("Orange")
    list.add("Pear")
    list.add("Grape")
    println(list)
    //————————————————————————
    //使用listOf()函数来出初始化集合
    val list2 = listOf("Apple","Banana","Orange","Pear","Grape")//创建list集合并添加元素,创建不可变的集合
   // list2.add("Watermelon")//不可向不可变集合添加元素
    for(fruit in list2){//使用循环来遍历list2,遍历到的元素存放在fruit中
        println(fruit)
    }
    //使用mutableListOf()函数创建可变的集合
    val  list3 = mutableListOf("Apple","Banna","Orange","Pear","Grape")
    list3.add("Watermelon")//向集合中添加元素
    for (fruit2 in list3){//使用循环来遍历list3,遍历到的元素存放在fruit2中
        println(fruit2)
    }

}

map

package Lambda

class map {

}

fun main() {
    //用类似java的方法通过put与get方法来存取数组元素
    val map = HashMap<String,Int>()
    map.put("Apple",1)
    map.put("Banana",2)
    map.put("Orange",3)
    map.put("Pear",4)
    map.put("Grape",5)
    //简化版
    val map2 = HashMap<String,Int>()
    map2["Apple"]=1//存数组元素
    map2["Banana"]=2
    map2["Orange"]=3
    map2["Pear"]=4
    map2["Grape"]=5
    val number=map2["Apple"]//通过键来取值
    println(number)
    //___________________________________________
    println("________________________________________________")
    //通过mapOf()与mutableMapof()来创建map集合,注意要留有空格,别挤在一起,否则无法识别
    val map3= mapOf("Apple" to 1 ,"Banana" to 2,"Orange" to 3,"Pear" to 4,"Grape" to 5)//传入初始的键值对组合来创建map集合
    for ((fruit,number)in map3){//用for in来进行遍历,键遍历到存放到fruit中,值遍历到存放到number中
        println("fruit is"+fruit+",number is "+number)
    }


}

set

package Lambda
//主函数必须单独定义,不能在类里面,当内部类
class set {

}
//set集合
fun main() {
    val set = setOf("Apple","Banna","Orange","Pear","Grape")//创建不可变集合
    for (fruit in set){
        println(fruit)
    }
    val set2 = mutableSetOf("Apple","Banna","Orange","Pear","Grape")//创建可变集合
    set2.add("西瓜")//为集合添加元素
    for (fruit2 in set2){
        println(fruit2)
    }
}

集合的函数式API(lambda表达式)

package 集合的函数式API
//需求:遍历所有水果集合,并取出单词最长的水果

class MaxLength {

}

fun main() {
    //最简单的写法
    val list= listOf("Apple","Banna","Orange","Pear","Grape","Watermelon")//定义不可变的集合
    var maxLengthFruit=""//创建存放最长长度的水果名称变量
    for (fruit in list){//用for in 循环遍历list ,结果存放在fruit
        if (fruit.length>maxLengthFruit.length){//如果遍历到的结果大于存放最长长度的水果名称变量
            maxLengthFruit=fruit//将遍历到的结果赋值给最长长度的水果名称变量
        }
    }
    println("1 max length fruit is "+maxLengthFruit)
println("______________________________________________________")
    //用集合的函数式API
    val list2= listOf("Apple","Banna","Orange","Pear","Grape","Watermelon")//定义不可变的集合
    val maxLengthFruit2=list2.maxBy { it.length }//maxBy根据我们传入的条件来遍历集合,从而找到该条件下的最大值
    println("2 max length fruit is "+maxLengthFruit2)
 println("_______________________________________________________")
    val list3= listOf("Apple","Banna","Orange","Pear","Grape","Watermelon")//定义不可变的集合
    val lambda={fruit2:String->fruit2.length}//定义lambda表达式,定义String 类型的frulit2变量,取其长度
    val maxLengthFruit3=list3.maxBy(lambda)//取list3里面lambda表达式中字符的最大值
    println("3 max length fruit is "+maxLengthFruit3)
    println("_______________________________________________________")
    //省去lambda变量,之间将lambda表达式传入
    val list4= listOf("Apple","Banna","Orange","Pear","Grape","Watermelon")//定义不可变的集合
    val maxLengthFruit4=list4.maxBy({fruit4:String->fruit4.length})//注意,里面还要有大括号,大括号的内容就是lambda表达式,小括号的内容是maxby的参数
    println("4 max length fruit is "+maxLengthFruit4)
    println("_______________________________________________________")
    //当Lambda参数式函数的最后一个参数时,可以将Lambda表达式移到函数括号外面
    val list5= listOf("Apple","Banna","Orange","Pear","Grape","Watermelon")//定义不可变的集合
    val maxLengthFruit5=list5.maxBy(){fruit5:String->fruit5.length}
    println("5 max length fruit is "+maxLengthFruit5)
    println("_______________________________________________________")
    //lambda参数是函数的唯一参数,还可以将函数括号省略
    val list6= listOf("Apple","Banna","Orange","Pear","Grape","Watermelon")//定义不可变的集合
    val maxLengthFruit6=list6.maxBy{fruit6:String->fruit6.length}
    println("6 max length fruit is "+maxLengthFruit6)
    println("_______________________________________________________")
    //lambda表达式参数列表可以不用声明参数类型
    val list7= listOf("Apple","Banna","Orange","Pear","Grape","Watermelon")//定义不可变的集合
    val maxLengthFruit7=list7.maxBy{fruit7->fruit7.length}
    println("7 max length fruit is "+maxLengthFruit7)
    println("_______________________________________________________")
    //当Lambda表达式的参数列表只有一个参数时,不必声明参数名,可以使用it关键字来替代
    val list8= listOf("Apple","Banna","Orange","Pear","Grape","Watermelon")//定义不可变的集合
    val maxLengthFruit8=list8.maxBy{it.length}
    println("8 max length fruit is "+maxLengthFruit8)
    println("_______________________________________________________")


}

判空辅助工具

fun doStudy(study:Study?){//Study类型的study变量可为空
study?.readBooks()//当study对象为空的时候什么都不做,当study对象不为空时调用readBooks()方法
}

val c = a ?: b //如果左边表达式的结果不为空就返回左边表达式的结果,否则就返回右边表达式的结果

!!为非空断言工具,写法时写在对象的后面加上!!,意在告诉kotlin,我非常确信这里的对象不会为空,所有不用你来帮我做空指针检查

let函数的使用

   let函数的介绍
/*
  ① fun dostudy(study:Study?){
   study?.readBook()
   }



   fun doStudy(study:Study?){
   if(study!=null){
   study.readBook()
   }
   if(study!=null){
   study.doHomework()
   }
   }
   ①等于②,一次if就能调用study对象的任何方法,但?的限制,每次调用study对象方法都要进行一次if判断,冗余



   let函数能够判断一次非空就调用非空对象的所有方法
   fun doStudy(study:Study?){
   study?.let{ stu->              //stu代表study的对象,名字可以随意写,调用所需,如果对象为空时候什么都不做,对象不为空时调用let函数
   stu.readBooks()                //let函数将study对象作为参数传到lambda表达式中
   stu.doHomework()
   }
   }



   fun doStudy(study:Study?){
   study?let{                   //如果不为空,就执行let函数
   it.readBooks()               //当lambda表达式的参数列表只有一个参数时,可以不用声明参数名,直接用it关键字来代替
   it.doHomework()

   }
   }



   let函数可以处理全局变量的判定
   var study:Study?=null
   fun  doStudy(){
   (study!=null){        //doStudy()函数中的参数变成一个全局变量
   study.readBooks()
   study.doHomework()
   }
   }
 */

字符串内嵌表达式

/*
 格式
 ${}
 "hello,${obj.name}.nice to meet you"
 当表达式仅有一个变量,可以将两边的大括号省略
 $
 "hello,$obj.name.nice to meet you"




 */

函数的参数默认值

/*
目标:给函数设定参数默认值
作用:在定义函数的时候给任意参数设定一个默认值,这样当调用此函数时就不会强制要求调用方为此参数传值,没有传值的情况下会自动设置参数的默认值


①主构造器和次构造器
class student(val sno:String,val grade:Int,name:String,age:Int):Person(name,age){//student类继承Person类,主构造函数
constructor(name:String,age:Int):this("",0,name,age)//对Person类进行实例化,调用4个参数的主构造函数,将缺失的两个参数赋值成初始值
constructor();this("",0){//对Person类进行实例化,调用两个参数的次构造函数,将两个参数赋值成初始值
}
}


用给函数设定参数默认值来实现①
class student(val sno:String="",val grade:Int=0,name:String="",age:Int=0):Person(name,age){//student类继承Person类,主构造函数



 */
fun printParams(num:Int,str:String="hello"){//给str的参数默认传值为hello
    println("num is $num , str is $str")//$为字符串内嵌表达式
}
fun main() {
printParams(123)//给num传值123,第二个不传值,为默认值;按照参数的定义顺序来传参
printParams2(str="world")//按照键值对的方式来传参,而num用默认值
}


fun printParams2(num:Int=100,str:String){//给num的参数默认传值为100
    println("num is $num , str is $str")//$为字符串内嵌表达式
}

延迟初始化和密封类

对变量延迟初始化

lateinit关键字:修饰后,可以晚些对这个变量进行初始化,不用一开始就将它赋值为null

MainActivity.kt

package com.example.a20200612study2

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.msg_left_item.view.*
import kotlinx.android.synthetic.main.msg_right_item.view.*
import java.text.FieldPosition

class MainActivity : AppCompatActivity() ,View.OnClickListener{
    private val msgList=ArrayList<Msg>()
    private lateinit var adapter:MsgAdapter//对变量进行延迟初始化

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initMsg()
        val  layoutManager= LinearLayoutManager(this)
        recyclerView.layoutManager=layoutManager//给RecyclerView指定LayoutManager
        adapter=MsgAdapter(msgList)//给RecyclerView指定适配器
        recyclerView.adapter=adapter
        send.setOnClickListener(this)
    }
    class Msg(val content:String,val type:Int){//content为消息内容,Type表示消息的类型
        companion object{//定义常量的关键字是const,在单例类、companion object或顶层方法才能实用const关键字
            const val TYPE_RECEIVED=0//TYPE_RECEIVED表示收到消息
            const val TYPE_SENT=1;//TYPE_SENT表示发送消息
        }
    }
    class MsgAdapter(val msgList: List<Msg>):RecyclerView.Adapter<RecyclerView.ViewHolder>(){
        inner class LeftViewHolder(view: View):RecyclerView.ViewHolder(view){//创建viewHolder用于缓存布局的控件
            val leftMsg:TextView=view.findViewById(R.id.leftMsg)
        }
        inner class RightViewHolder(view:View):RecyclerView.ViewHolder(view){//创建viewHolder用于缓存布局的控件
            val rightMsg:TextView=view.findViewById(R.id.rightMsg)
        }
        override  fun  getItemViewType(position:Int):Int{
            val msg=msgList[position]//根据postion来获取消息
            return msg.type//返回消息的类型
        }
        override fun onCreateViewHolder(parent:ViewGroup,viewType:Int)=if (viewType==Msg.TYPE_RECEIVED){//根据不同的viewType创建不同的界面
            val view= LayoutInflater.from(parent.context).inflate(R.layout.msg_left_item,parent,false)
            LeftViewHolder(view)//根据不同的viewType来加载不同的ViewHolder
        }else{
            val view=LayoutInflater.from(parent.context).inflate(R.layout.msg_right_item,parent,false)
            RightViewHolder(view)//根据不同的viewType来加载不同的ViewHolder
        }
        override  fun onBindViewHolder(holder:RecyclerView.ViewHolder,position:Int){
            val msg=msgList[position]
            when(holder){//判断ViewHolder类型
                is LeftViewHolder->holder.leftMsg.text=msg.content//is相当于if,如果是leftViewHolder就将内容显示到左边的消息布局
                is RightViewHolder->holder.rightMsg.text=msg.content//is相当于if,如果是RightViewHolder就将内容显示到右边的消息布局
                else -> throw  IllegalArgumentException()
            }
        }
override  fun getItemCount()=msgList.size
    }

    override fun onClick(v: View?) {
     when(v){
         send->{
             val content=inputText.text.toString()//获取EditText中的内容
             if (content.isNotEmpty()){//如果内容不为空字符串
                 val msg = Msg(content,Msg.TYPE_SENT)//创建一个新的Msg对象
                 msgList.add(msg)//Msg对象添加到msgList列表中去
                 adapter.notifyItemInserted(msgList.size-1)//调用适配器的方法,当有新消息时,刷新RecyclerView中的显示,对变量进行延迟初始化后,就不用进行判空处理
                 //notifyDataSetChanged()方法,将RecyclerView 中所有可谏的元素全部刷新
                 recyclerView.scrollToPosition(msgList.size-1)//将RecyclerView定位到最后一行
                 inputText.setText("")//清空输入框中的内容
             }
         }
     }
    }
    private  fun initMsg(){//初始化几条数据在RecyclerView zhong xianshi
        val  msg1=Msg("你好",Msg.TYPE_RECEIVED)
        msgList.add(msg1)
        val msg2=Msg(" 你好,你是谁?",Msg.TYPE_SENT)
        msgList.add(msg2)
        val  msg3=Msg("我是tom,很高兴和你谈话",Msg.TYPE_RECEIVED)
        msgList.add(msg3)
    }
}

用代码来判断全局变量是否完成初始化

package com.example.a20200612study2

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.msg_left_item.view.*
import kotlinx.android.synthetic.main.msg_right_item.view.*
import java.text.FieldPosition

class MainActivity : AppCompatActivity() ,View.OnClickListener{
    private val msgList=ArrayList<Msg>()
    private lateinit var adapter:MsgAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initMsg()
        val  layoutManager= LinearLayoutManager(this)
        recyclerView.layoutManager=layoutManager//给RecyclerView指定LayoutManager
        /**************************判断全局变量是否被初始化****************/
      if (!::adapter.isInitialized) {//::adapter.isInitialized判断adapter变量是否已经初始化,!来进行取反,如果没有初始化
            adapter = MsgAdapter(msgList)//给RecyclerView指定适配器,对adapter变量进行初始化
        }
        /**************************判断全局变量是否被初始化****************/
        recyclerView.adapter=adapter
        send.setOnClickListener(this)
    }
    class Msg(val content:String,val type:Int){//content为消息内容,Type表示消息的类型
        companion object{//定义常量的关键字是const,在单例类、companion object或顶层方法才能实用const关键字
            const val TYPE_RECEIVED=0//TYPE_RECEIVED表示收到消息
            const val TYPE_SENT=1;//TYPE_SENT表示发送消息
        }
    }
    class MsgAdapter(val msgList: List<Msg>):RecyclerView.Adapter<RecyclerView.ViewHolder>(){
        inner class LeftViewHolder(view: View):RecyclerView.ViewHolder(view){//创建viewHolder用于缓存布局的控件
            val leftMsg:TextView=view.findViewById(R.id.leftMsg)
        }
        inner class RightViewHolder(view:View):RecyclerView.ViewHolder(view){//创建viewHolder用于缓存布局的控件
            val rightMsg:TextView=view.findViewById(R.id.rightMsg)
        }
        override  fun  getItemViewType(position:Int):Int{
            val msg=msgList[position]//根据postion来获取消息
            return msg.type//返回消息的类型
        }
        override fun onCreateViewHolder(parent:ViewGroup,viewType:Int)=if (viewType==Msg.TYPE_RECEIVED){//根据不同的viewType创建不同的界面
            val view= LayoutInflater.from(parent.context).inflate(R.layout.msg_left_item,parent,false)
            LeftViewHolder(view)//根据不同的viewType来加载不同的ViewHolder
        }else{
            val view=LayoutInflater.from(parent.context).inflate(R.layout.msg_right_item,parent,false)
            RightViewHolder(view)//根据不同的viewType来加载不同的ViewHolder
        }
        override  fun onBindViewHolder(holder:RecyclerView.ViewHolder,position:Int){
            val msg=msgList[position]
            when(holder){//判断ViewHolder类型
                is LeftViewHolder->holder.leftMsg.text=msg.content//is相当于if,如果是leftViewHolder就将内容显示到左边的消息布局
                is RightViewHolder->holder.rightMsg.text=msg.content//is相当于if,如果是RightViewHolder就将内容显示到右边的消息布局
                else -> throw  IllegalArgumentException()
            }
        }
override  fun getItemCount()=msgList.size
    }

    override fun onClick(v: View?) {
     when(v){
         send->{
             val content=inputText.text.toString()//获取EditText中的内容
             if (content.isNotEmpty()){//如果内容不为空字符串
                 val msg = Msg(content,Msg.TYPE_SENT)//创建一个新的Msg对象
                 msgList.add(msg)//Msg对象添加到msgList列表中去
                 adapter.notifyItemInserted(msgList.size-1)//调用适配器的方法,当有新消息时,刷新RecyclerView中的显示
                 //notifyDataSetChanged()方法,将RecyclerView 中所有可谏的元素全部刷新
                 recyclerView.scrollToPosition(msgList.size-1)//将RecyclerView定位到最后一行
                 inputText.setText("")//清空输入框中的内容
             }
         }
     }
    }
    private  fun initMsg(){//初始化几条数据在RecyclerView zhong xianshi
        val  msg1=Msg("你好",Msg.TYPE_RECEIVED)
        msgList.add(msg1)
        val msg2=Msg(" 你好,你是谁?",Msg.TYPE_SENT)
        msgList.add(msg2)
        val  msg3=Msg("我是tom,很高兴和你谈话",Msg.TYPE_RECEIVED)
        msgList.add(msg3)
    }
}

使用密封类优化代码

密封类的关键字是 sealed class,使用密封类可以使判断语句更严谨,不必写else 语句,但必须处理子类里面的所有条件

密封类及其所有子类只能定义在同一文件的顶层位置,不能嵌套在其他类中

package com.example.a20200613study

import java.lang.Exception
import kotlin.IllegalArgumentException

sealed class Result
class Success(val msg:String):Result()//密封类可继承
class Failure(val error:Exception):Result()
fun getResultMsg(result: Result)=when(result){//接收一个result参数,用when判断result参数的值
    is Success->result.msg//如果result为Success  返回result的消息
    is Failure -> "Error is ${result.error.message}"
}
//class UnKnown :Result()//因为判断里没有unknown分支,所以方法必然报错

猜你喜欢

转载自blog.csdn.net/u013074761/article/details/106485141