本文目录:
- 一、Kotlin特性
- 1、变量
- 2、常量
- 3、类型推断:
- 4、null类型限制:
- 5、分支(条件语句)
- 5.1 分支1:if-else
- 5.2 分支2:when、else、-> 的搭配
- 6、函数:
- 6.1 声明定义:
- 6.2 特性简化:
- 6.3 匿名函数:
- 6.4 高阶函数:参数有函数的
- 7、类(属性+函数)
- 属性默认权限:public
- 构造函数的构建:
- 类的实例化(使用构造函数)、类对象的属性的调用:
- 类函数:
- 二、Kotlin在安卓开发中常见的代码总结:
- 1、使用 Fragment
- 2、推迟变量的初始化:late-init
- 3、事件的匿名函数:
- 4、伴生对象:companion object
- 5、属性委托:by
- 6、null的注意:
- 6.1 在Java中书写习惯:方便与kotlin协同
- 6.2 处理kotlin中的null值:
- 7、变量初始化:
- 7.1 在类声明的时候直接初始化:
- 7.2 在init块中初始化
- 7.3 先null,后面尽快初始化
- 7.4 lateinit延迟初始化:比上一个好
参考:Android官网:https://developer.android.google.cn
一、Kotlin特性
1、变量
var
count: Int = 10
var
:变量count
:变量名Int
:整型,类似的还有:Byte、Short、Long、Float 和 Double注意
:声明的时候,如果不使用类型推断,则变量名和变量类型使用英文冒号连为一体。使用的时候,只需要使用变量名即可。句尾不需要写分号。
如: count=20
2、常量
val
languageName: String = “Kotlin”把var的
r
改成l
即可,但是不可再次赋值,因为是常量。
3、类型推断:
val
languageName = “Kotlin”
val
upperCaseName = languageName.toUpperCase()显然
languageName
是字符串String
类型
在 声明变量 的时候,可以 只赋值,而省略掉 变量的类型。
此时,系统会根据 赋值的字面值 来推断该变量的数据类型,从而节省代码量。
4、null类型限制:
//错误示范:
val
languageName: String = null
- 注意:以上代码
错误
。- 原因:Kotlin语言对变量的null类型进行了限制,
默认情况下,变量不能为null类型
,也就是变量必须要有对应变量类型的值。- 废话:这种方式虽然让Kotlin语言难了一点,但是保证了代码的安全(因为如果变量的值为null,并且被程序使用,可能会让应用无故崩溃闪退,这是谁也不愿意看到的)
//正确示范:类型后面加个问号即可
val
languageName:String?
= null上面的
String?
表示:变量可以拥有两种类型:
1、String类型:可以把字符串赋值给它
2、null类型:可以把null赋值给它
5、分支(条件语句)
5.1 分支1:if-else
if (count == 42) {
println("I have the answer.")
} else {
println("The answer eludes me.")
}
if (count == 42) {
println("I have the answer.")
} else if (count > 35) {
println("The answer is close.")
} else {
println("The answer eludes me.")
}
//上面的代码可以简写成:
val answerString: String = if (count == 42) {
"I have the answer."
} else if (count > 35) {
"The answer is close."
} else {
"The answer eludes me."
}
println(answerString)
//上面代码的说明:
if-else语句中最后一个字面值,都可以表示为该分支(最终只有一条为真)的返回值。
上面的语句的意思就是使用一个变量来接受if-else分支结构的返回值。
在一定程度上减少了println的代码
5.2 分支2:when、else、-> 的搭配
when{}
条件-> 语句
else->语句
val answerString = when {
count == 42 -> "I have the answer."
count > 35 -> "The answer is close."
else -> "The answer eludes me."
}
println(answerString)
6、函数:
6.1 声明定义:
// fun 函数名():返回类型,没有时可不写
fun generateAnswerString(): String {
val answerString = if (count == 42) {
"I have the answer."
} else {
"The answer eludes me"
}
return answerString
}
//带参函数:
fun generateAnswerString(countThreshold: Int): String {
val answerString = if (count > countThreshold) {
"I have the answer."
} else {
"The answer eludes me."
}
return answerString
}
6.2 特性简化:
//利用if-else返回值的特性简化代码:
fun generateAnswerString(countThreshold: Int): String {
return if (count > countThreshold) {
"I have the answer."
} else {
"The answer eludes me."
}
}
//再次简化代码(简单函数,可省略return,用赋值符号替代):
fun generateAnswerString(countThreshold: Int): String = if (count > countThreshold) {
"I have the answer"
} else {
"The answer eludes me"
}
6.3 匿名函数:
val stringLengthFunc: (String) -> Int = { input ->
input.length
}
//说明(难度系数5星):
1、常量val,变量名为stringLengthFunc,这个变量用来干嘛呢?看它冒号后面的
数据类型,(String) -> Int,这个可能最难理解。
(参数类型)->函数返回值类型
1、首先,小括号我们可以理解成函数,因为函数的函数名后面常常都携带一个小括号。
至于这里为什么没有函数名?因为这是匿名函数呀,自然要省略函数名。
2、其次,箭头和后面的Int又是什么意思呢?我们都知道,函数有两个非常重要的组成部分
一个是函数名,另一个是函数返回类型。因为是匿名函数,所以函数名没了,
而函数返回类型却不能省略,所以,Int这里就是它的函数返回类型。
2、后面的赋值符号=又是什么意思:
这就是前面说的,省略return,使用赋值符号取而代之的骚操作,
没有return的时候就不会这样写了,所以他就是return的简写版而已。
3、最后面的:input ->
input.length
其实这就像lambda表达式一样,input是实参,箭头后面才是函数体。
注意:如果匿名函数没有返回值(自然也就没有return),那就会相当于全部省略,
只保留大括号,让人难以看出。今后要是遇到匿名函数,要心里留个底
避免傻傻看不出。
6.4 高阶函数:参数有函数的
fun stringMapper(str: String, mapper: (String) -> Int): Int {
// Invoke function
return mapper(str)
}
//大家一定要习惯匿名函数的:(参数类型)->函数返回值类型 这种类型组合。
//还要习惯类型后置的这种写法。最初看起来很别扭,但真的有用。
mapper:函数引用(你可以理解成一个函数指针)
//高阶函数调用:
stringMapper("Android", { input ->
input.length
})
//如果函数参数在最后一个:参数可以写在外部————
stringMapper("Android") { input ->
input.length
}
7、类(属性+函数)
属性默认权限:public
class Car {
val wheels = listOf<Wheel>()
}
构造函数的构建:
class Car(val wheels: List<Wheel>){...}
//注意:
构造函数可以直接在声明类的类名后面当作函数一样传入函数参数
类的实例化(使用构造函数)、类对象的属性的调用:
val car = Car() // construct a Car
val wheels = car.wheels // retrieve the wheels value from the Car
类函数:
class Car(val wheels: List<Wheel>) {//构造函数参数可以直接写在这
private val doorLock: DoorLock = ...//变量属性
fun unlockDoor(key: Key): Boolean {//类内函数
// Return true if key is valid for door lock, false otherwise
}
}
二、Kotlin在安卓开发中常见的代码总结:
1、使用 Fragment
class LoginFragment : Fragment()//继承
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.login_fragment, container, false)
}
//上诉代码说明:override:表示后面的函数是重写父类Fragment的已有的函数。
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
}
//上诉代码说明:super表示父类的一个实例,如果需要调用父类的函数(代码),就需要用super
2、推迟变量的初始化:late-init
class LoginFragment : Fragment() {
//变量定义的时候可以先不初始化,但尽量尽快初始化
private lateinit var usernameEditText: EditText
private lateinit var passwordEditText: EditText
private lateinit var loginButton: Button
private lateinit var statusTextView: TextView
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
usernameEditText = view.findViewById(R.id.username_edit_text)
passwordEditText = view.findViewById(R.id.password_edit_text)
loginButton = view.findViewById(R.id.login_button)
statusTextView = view.findViewById(R.id.status_text_view)
}
...
}
3、事件的匿名函数:
//button的点击事件,因为没有返回值,所以匿名函数几乎全部省略,其实这里是使用匿名函数。
//如果是Java,可能会这样写:loginButton.setOnClickListener( a,{...});
//但是Kotlin没有返回值的匿名函数几乎全部隐匿,甚至函数调用的小括号都省略了。
loginButton.setOnClickListener {
val authSuccessful: Boolean = viewModel.authenticate(
usernameEditText.text.toString(),
passwordEditText.text.toString()
)
if (authSuccessful) {
// Navigate to next screen
} else {
statusTextView.text = requireContext().getString(R.string.auth_failed)
}
}
4、伴生对象:companion object
class LoginFragment : Fragment() {
...
companion object {//相当于Java的static变量,仅存一份实例,伴随该类
private const val TAG = "LoginFragment"
}
}
5、属性委托:by
注意:属性委托使用反射,这样会增加一些性能开销。这种代价换来的是简洁的语法,可让您节省开发时间。
//在初始化变量(对象)的时候,常常需要其他父类的支持:
private val viewModel: LoginViewModel by viewModels()
6、null的注意:
6.1 在Java中书写习惯:方便与kotlin协同
public class Account implements Parcelable {
public final String name;
public final String type;
private final @Nullable String accessId;//可以为null
...
}
public class Account implements Parcelable {
public final @NonNull String name;//不可为null
...
}
6.2 处理kotlin中的null值:
1、变量后面带 !!
运算符:
断定name为非null,强制执行,但如果为null就会报异常。所以这种写法其实回到了Java的模式上了。
val account = Account("name", "type")
val accountName = account.name!!.trim()
2、更安全的写法:?.
+?:
val account = Account("name", "type")
val accountName = account.name?.trim()
//为了避免null值向下传递()虽然使用?.以后该语句不会报异常,但是结果仍会为null
//建议使用下面的写法。如果是null,就用最后的值赋值给最左边的变量accountName(失败后的退路)
val accountName = account.name?.trim() ?: "Default name"
骚操作:
fun validateAccount(account: Account?) {
val accountName = account?.name?.trim() ?: "Default name"
// account变量在此处之外不能为null。
//提前返回
account ?: return
...
}
7、变量初始化:
7.1 在类声明的时候直接初始化:
class LoginFragment : Fragment() {
val index: Int = 12//初始化变量
}
7.2 在init块中初始化
class LoginFragment : Fragment() {
val index: Int
init {//在块中初始化
index = 12
}
}
7.3 先null,后面尽快初始化
class LoginFragment : Fragment() {
private var statusTextView: TextView? = null//先可null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
statusTextView = view.findViewById(R.id.status_text_view)//初始化
statusTextView?.setText(R.string.auth_failed)
}
}
7.4 lateinit延迟初始化:比上一个好
class LoginFragment : Fragment() {
private lateinit var statusTextView: TextView//延迟初始化
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
statusTextView = view.findViewById(R.id.status_text_view)//初始化
statusTextView.setText(R.string.auth_failed)
}
}