0
点赞
收藏
分享

微信扫一扫

Android开发学习之路--Kotlin之Android开发使用心得和注意事项


前言

1 @Autowired需要@JvmField注解

@Autowired(name = "test")
@JvmField
var currentDate: Long = 0

当我们用到类似于阿里的ARouter的时候,会发现@Autowired不起作用,其实是注入代码为了减少反射,使用的字段赋值的方式来注入的,Kotlin 默认会生成 set/get 方法,并把属性设置为 private。这时就可以使用 @JvmField 注解,编译之后该属性将直接暴露。

2 不用写findViewById

先看一个布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:id="@+id/tv1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<Button
android:id="@+id/bt1"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

</LinearLayout>

我们在Activity的onCreate中就可以直接这么写

tv1.text = "hello kotlin" //textview填内容
bt1.setOnClickListener { //监听button事件
toast("Hello Kotlin")
}

但是如果是Fragment中的话,需要注意一点就是:

  • 不能在onCreateView方法里用view,不然会出现空指针异常,需要在onViewCreate里。因为kotlin的插件用了getView来findViewById,在onViewCreate后才获取到view.

3 with,apply

减少代码量,这个可以看下上一篇《 Android开发学习之路–Kotlin之常用表达式及函数》,这里不做过多介绍

4 fun内部也可以定义fun 利用局部函数抽取重复代码

可以在函数内部定义函数,来简化代码

比如一个findView的函数如下:

fun initView() {
private var mTv1:TextView = itemView.findViewById(R.id.tv_1) as TextView
private var mTv2:TextView = itemView.findViewById(R.id.tv_2) as TextView
private var mTv3:TextView = itemView.findViewById(R.id.tv_3) as TextView
}

我们可以写一个内部函数,然后可以简化如下:

fun initView() {
private fun findTextView(id: Int) = itemView.findViewById(id) as TextView

private var mTv1 = findTextView(R.id.tv_1)
private var mTv2 = findTextView(R.id.tv_2)
private var mTv3 = findTextView(R.id.tv_3)
}

5 匿名内部类

kotlin中没有java的new关键字,所以在调用类似于监听的方法中的匿名内部类时候,需要用到object,如下所示

addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabReselected(tab: TabLayout.Tab?) {
}

override fun onTabUnselected(tab: TabLayout.Tab?) {

}

override fun onTabSelected(tab: TabLayout.Tab?) {

}
})

6 代码注入 kapt

编译器的依赖关系需要使用kapt

kapt "com.google.dagger:dagger-compiler:$DAGGER_COMPILER_VERSION"

7 static方法

在kotlin中使用类似java的静态方法,使用companion object

class Utils {
companion object {
fun test() {
toast("Hello kotlin")
}
}
}

上述可以使用Utils.test()来调用

8 单表达式函数

a+b,或者比大小的函数,可以写的很简单:

fun sum(a:Int, b:Int) = a+b

9 使用数据类来快速实现model类

一般java中我们声明一个model类,需要设置属性为private,然后实现set/get方法,而kotlin中,我们只要简单地使用data就可以了。

//用data关键词来声明一个数据类,除了会自动实现get set,还会自动生成equals hashcode toString
data class person(
var name:String = "",
var sex:String = "male"
)

若要实现Parcelable,需要在Builder.gradle中加入plugin

apply plugin: 'kotlin-android-extensions'

......

androidExtensions {
experimental = true
}

具体注解如下:

@Parcelize
data class person(
var name:String = "",
var sex:String = "male"
): Parcelable

10 Lambda表达式简化OnClickListener

  • 比如一个Click事件

TextView textView = new TextView(context);
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//do something
}
});

  • lambda的方式

textView.setOnClickListener({ v ->
{
//do something
}
})

  • 当lambda的参数没有使用时可以省略,省略的时候用it来替代

textView.setOnClickListener({ 
//do something
})

  • 函数如果没有其他参数可以省略,最后变成了

textView.setOnClickListener {
//do something
}

11 高阶函数+lambda简化代码

当我们监听TabLayout的select的时候,一般我们这么写:

tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabReselected(tab: TabLayout.Tab?) {
//do something
}

override fun onTabUnselected(tab: TabLayout.Tab?) {
//do something
}

override fun onTabSelected(tab: TabLayout.Tab?) {
//do something
}
})

有时候我们只需要调用其中的一个方法,则显得代码臃肿。这个时候高阶函数和lambda就可以派上用场了。

首先我们实现一个类实现TabLayout.OnTabSelectedListener接口。然后定义三个函数,传入的参数分别是函数,然后当接口中的方法被回调后,再调用具体传入的函数的方法。

class _OnTabSelectedListener : TabLayout.OnTabSelectedListener {
private var _onTabReselected: ((tab: TabLayout.Tab?) -> Unit)? = null
private var _onTabUnselected: ((tab: TabLayout.Tab?) -> Unit)? = null
private var _onTabSelected: ((tab: TabLayout.Tab?) -> Unit)? = null

override fun onTabReselected(tab: TabLayout.Tab?) {
_onTabReselected?.invoke(tab)
}

fun onTabReselected(func: (tab: TabLayout.Tab?) -> Unit) {
_onTabReselected = func
}

override fun onTabUnselected(tab: TabLayout.Tab?) {
_onTabUnselected?.invoke(tab)
}

fun onTabUnselected(func: (tab: TabLayout.Tab?) -> Unit) {
_onTabUnselected = func
}

override fun onTabSelected(tab: TabLayout.Tab?) {
_onTabSelected?.invoke(tab)
}

fun onTabSelected(func: (tab: TabLayout.Tab?) -> Unit) {
_onTabSelected = func
}
}

然后我们写一个TabLayout的扩展函数,入参是一个函数,是我们上面写好的这个类的函数,返回一个Unit

fun TabLayout.addOnTabSelectedListener(func: _OnTabSelectedListener.() -> Unit) {
val listener = _OnTabSelectedListener()
listener.func()
addOnTabSelectedListener(listener)
}

最后我们可以把代码写成这样:

addOnTabSelectedListener {
onTabUnselected {
//do something
}

onTabSelected {
//do something
}

onTabReselected {
//do something
}
}

当然,可以省略onTabUnselected, onTabSelected,onTabReselected的任何一个或者全部。

12 委托模式(by 关键字)

  • 先定义两个接口Base1和Base2

interface Base1 {
fun print1()
}

interface Base2 {
fun print2()
}

  • 两个实现类分别实现Base1和Base2

class BaseImpl(val x: Int) : Base1 {
override fun print1() {
Log.d("BaseImpl", "print1 -> $x")
}
}

class BaseImpl2(val x: Int) : Base2 {
override fun print2() {
Log.d("BaseImpl", "print2 -> $x")
}
}

  • 接着用代理

class PrintTest(
b1: Base1,
b2: Base2
) : Base1 by b1, Base2 by b2

  • 具体实现

val print1 = BaseImpl(10)
val print2 = BaseImpl2(5)
PrintTest(print1, print2).print1()
PrintTest(print1, print2).print2()

// 输出
D/BaseImpl: print1 -> 10
D/BaseImpl: print2 -> 5

PrinterTest没有实现接口Base1的方法print1(),而是通过关键字by,将实现委托给了b1


举报

相关推荐

0 条评论