前言
记录自第一行代码第三版
变量
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分支,所以方法必然报错