Kotlin 用于 Android 开发要点整理:01

刷了两遍 Kotlin 语言中文站 的 Kotlin 语法,终于尝试在实际的开发环境中应用 Kotlin 进行 Android 开发,刚开始还不敢在逻辑操作类中应用,故选择较为简单的 View 类,即使这样,也会有很多坑需要掉填掉填…

1、Android 开发时,很多变量是在 onCreate() 中初始化的,但由于Kotlin的空安全检查机制,如果我们不在定义处初始化,那么我们可以采用关键字 “lateinit”,延迟初始化:

private var mTvTitle: TextView? = null
private var mBtnBack: ImageButton? = null
private lateinit var mTvTitle: TextView
private lateinit var mBtnBack: ImageButton

没有延迟初始化前,可空变量每次调用属性时,都得加 “?”【安全调用操作符,写作 “?.”】,延迟初始化后就不用了:

mTvTitle?.visibility = View.VISIBLE
mBtnBack?.visibility = View.VISIBLE
mTvTitle.visibility = View.VISIBLE
mBtnBack.visibility = View.VISIBLE

2、用 Java 写代码时,习惯了用各种 set 来设置属性,Kotlin 进行 Android 开发时也行,只是 AS 没有代码提示,要手打,而 Kotlin 默认的是 “要使用一个属性,只要用名称引用它即可,就像 Java 中的字段”:

mTvTitle.setVisibility(View.VISIBLE)
mTvTitle.setText(title)
mRecyclerView.setLayoutManager(LinearLayoutManager(this))
mRecyclerView.setAdapter(mOldCareRecyclerAdapter)      
mTvTitle.visibility = View.VISIBLE
mTvTitle.text = title
mRecyclerView.layoutManager = LinearLayoutManager(this)
mRecyclerView.adapter = mOldCareRecyclerAdapter

理由同上,只是这里省略了 intent 前的 “this.”:

val title:String = getIntent().getStringExtra(getString(R.string.consult_title_sign))
val title: String = intent.getStringExtra(getString(R.string.consult_title_sign))

3、还记得那个 .class 么,Kotlin 有两种写法:

 val webIntent = Intent(mContext, CommonWebEntryActivity().javaClass)
 val webIntent = Intent(mContext, CommonWebEntryActivity::class.java)

4、Android 开发中有各种设置监听的地方,虽然刷了两遍语法,但是用到实际的开发环境还是有点蒙,最终通过 AS 的自动转化代码功能,得到了 “kotlin 样式” 这种写法,是不是很溜很简洁?!但是做为一个老风格的 Android 开发,个人没能那么快地转化风格,通过摸索,还是通过 “java - kotlin 样式” 这种样式做过度先,很多人都说 “抱歉!不要用Java的语法思维来写Kotlin”,但对个人来说,还是需要一个过程:

// Java 样式
mRefreshLayout.setOnRefreshListener(new OnRefreshListener() {
	@Override
	public void onRefresh(final RefreshLayout refreshLayout) {
		refreshLayout.getLayout().postDelayed(new Runnable() {
			@Override
			public void run() {
				... ...
			}
		}, 1000);
	}
});
// java - kotlin 样式
mRefreshLayout?.setOnRefreshListener(object : OnRefreshListener {
	override fun onRefresh(refreshLayout: RefreshLayout?) {
		refreshLayout?.layout?.postDelayed({
			... ...
		}, 1000)
	}
})
// kotlin 样式【Java8 也开始支持 “Lambda表达式”】
mRefreshLayout.setOnRefreshListener { refreshLayout ->
	refreshLayout.layout.postDelayed({
		... ...
	}, 1000)
}

PSJava 8 Lambda 表达式

刚开始确实不是很适应这种用法,但习惯之后还是蛮简单的:

mRefreshLayout.setOnRefreshListener(new OnRefreshListener() {
	@Override
	public void onRefresh(final RefreshLayout refreshLayout) {
		refreshLayout.getLayout().postDelayed(new Runnable() {
			@Override
			public void run() {
				... ...
			}
		}, 1000);
	}
});

去掉多余的代码:

mRefreshLayout.setOnRefreshListener(() {
	(final RefreshLayout refreshLayout) {
		refreshLayout.getLayout().postDelayed(() {
			{
				... ...
			}
		}, 1000);
	}
});

给点语法糖:

mRefreshLayout.setOnRefreshListener { refreshLayout ->
	refreshLayout.layout.postDelayed({
		... ...
	}, 1000)
}

完整的:

mRefreshLayout.setOnRefreshListener { (refreshLayout) ->
	{
		refreshLayout.layout.postDelayed( ()->{...}, 1000)
	}
}

PS:说到底 Lambda 表达式是一种语法糖,允许用函数表达式做参数,代替原先的匿名内部类;而 “()” 里面是原先匿名内部类要执行的方法中的参数,"{}" 里面是要执行的方法体;然后语法糖再简化,如果所需参数只有一个或一个都没有时,"()" 可以省略,方法体只有一条时,"{}" 可以省略;惊不惊喜,意不意外 … …

高阶函数与 lambda 表达式 - Kotlin 语言中文站 https://www.kotlincn.net/docs/reference/lambdas.html
Kotlin 函数都是头等的,这意味着它们可以存储在变量与数据结构中、作为参数传递给其他高阶函数以及从其他高阶函数返回。可以像操作任何其他非函数值一样操作函数。为促成这点,作为一门静态类型编程语言的 Kotlin 使用一系列函数类型来表示函数并提供一组特定的语言结构,例如 lambda 表达式。
① 头等函数(first-class function):指在程序设计语言中,函数被当作头等公民,这意味着,函数可以作为别的函数的参数、函数的返回值,赋值给变量或存储在数据结构中
② 高阶函数:高阶函数是将函数用作参数或返回值的函数。

Lambda 表达式与匿名函数
lambda 表达式与匿名函数是“函数字面值”,即未声明的函数, 但立即做为表达式传递。考虑下面的例子:
		max(strings, { a, b -> a.length < b.length })
函数 max 是一个高阶函数,它接受一个函数作为第二个参数。 其
第二个参数是一个表达式,它本身是一个函数,即函数字面值,它等价于以下命名函数:
		fun compare(a: String, b: String): Boolean = a.length < b.length

1、Lambda 表达式语法
Lambda 表达式的完整语法形式如下:
		val sum = { x: Int, y: Int -> x + y }
lambda 表达式总是括在花括号中, 完整语法形式的参数声明放在花括号内,并有可选的类型标注, 函数体跟在一个 -> 符号之后。
如果推断出的该 lambda 的返回类型不是 Unit,那么该 lambda 主体中的最后一个(或可能是单个)表达式会视为返回值。
如果我们把所有可选标注都留下,看起来如下:
		val sum: (Int, Int) -> Int = { x, y -> x + y }

2、将 lambda 表达式传给最后一个参数
在 Kotlin 中有一个约定:如果函数的最后一个参数接受函数,那么作为相应参数传入的 lambda 表达式可以放在圆括号之外:
		val product = items.fold(1) { acc, e -> acc * e }
如果该 lambda 表达式是调用时唯一的参数,那么圆括号可以完全省略:
		run { println("...") }

3、it:单个参数的隐式名称
一个 lambda 表达式只有一个参数是很常见的。
如果编译器自己可以识别出签名,也可以不用声明唯一的参数并忽略 ->。 该参数会隐式声明为 it:
		ints.filter { it > 0 } // 这个字面值是“(it: Int) -> Boolean”类型的

4、从 lambda 表达式中返回一个值
我们可以使用限定的返回语法从 lambda 显式返回一个值。 否则,将隐式返回最后一个表达式的值。
因此,以下两个片段是等价的:
		ints.filter {
		    val shouldFilter = it > 0 
		    shouldFilter
		}
		ints.filter {
		    val shouldFilter = it > 0 
		    return@filter shouldFilter
		}
这一约定连同在圆括号外传递 lambda 表达式一起支持 LINQ-风格 的代码:
		strings.filter { it.length == 5 }.sortedBy { it }.map { it.toUpperCase() }

5、下划线用于未使用的变量(自 1.1 起)
如果 lambda 表达式的参数未使用,那么可以用下划线取代其名称:
		map.forEach { _, value -> println("$value!") }
		map.forEach { _, value -> println("$value!") }

5、开发中一个数据量需要判断 null,这在用 Java 开发时,是很常见的情况,但是当我对一个延迟初始化的变量进行 null 判断时,出现了下面这种情况:

private var mMutableList: MutableList<CompanyBean>? = null

private lateinit var mMutableList: MutableList<CompanyBean>

“Condition ‘mMutableList != null’ is always ‘true’”??想想也是,你都告诉编译器 “会初始化,只是延迟”:

但是,还是得判断 null,所以查 Api:

错误写法:

正确写法:

if (::mMutableList.isLateinit) mMutableList.clear()

反射 - Kotlin 语言中文站 https://www.kotlincn.net/docs/reference/reflection.html

这里有个逻辑上的误区:
我们为什么要清空 list,就是因为 list 有数据,所以,直接判断是否为 Empty 就行,而不要以 Java 的开发习惯去判断是否为 null,因为我们已经用 “lateinit” 告诉编译器,我们会初始化,只是延迟而已。

// 提示 warning
if (mMutableList != null) mMutableList.clear()
// Java 习惯
if (::mMutableList.isLateinit) mMutableList.clear()
// 直接判断是否为 Empty
if (mMutableList.isNotEmpty()) mMutableList.clear() 

最后说两句:
第一次在实际的开发环境中应用 Kotlin 进行 Android 开发,总觉得得瞎写些什么 …

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值