코 틀린 새로운 기능 (자바 언어로 표시되지 않습니다)

필요가 없습니다 findViewById를

레이아웃에 정의

<TextView
    android:id="@+id/tv_content"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello World!" />

직접 텍스트 텍스트 뷰에서

tv_content.text = "改变文本"

람다

자바 JDK 람다 표현식이 추가되었습니다하지만 유행하지 않았지만, 지금은 코 틀린은 좋은 선택이 될 것입니다 함께

tv_content.setOnClickListener(View.OnClickListener(

    fun(v : View) {
        v.visibility = View.GONE
    }
))

그것은 지금 람다 식을 단순화 할 수있다

tv_content.setOnClickListener { v -> v.visibility = View.GONE }

기능 변수

코 틀린 함수 구문은 변수로서 전달 될 수있다

var result = fun(number1 : Int, number2 : Int) : Int {
    return number1 + number2
}

이 함수의 변수 사용

println(result(1, 2))

공간 보안

널 객체를 처리하기 위해 우리를 강요하지 않고 자바의 경우, 종종 처리 객체가 컴파일시에 비어 있거나으로 컴파일되지 않습니다 여부를해야합니다, NullPointerException이 널 포인터가 이제 코 틀린 빈 객체가 제한되어 들어, 표시의 원인

객체가 비어 있지 않은 경우, 객체는 직접 사용할 수 있습니다

fun getText() : String {
    return "text"
}

val text = getText()
print(text.length)

경우 개체가 비어있을 수 있으며, 객체가 비어 있는지 결정해야한다 곳

fun getText() : String? {
    return null
}

val text = getText()
if (text != null) {
    print(text.length)
}

// 如果不想判断是否为空,可以直接这样,如果 text 对象为空,则会报空指针异常,一般情况下不推荐这样使用
val text = getText()
print(text!!.length)

// 还有一种更好的处理方式,如果 text 对象为空则不会报错,但是 text.length 的结果会等于 null
val text = getText()
print(text?.length)

방법 지원 기본 매개 변수 추가

자바에, 우리는 방법 및 다수의 오버로드로 확장 될 수

public void toast(String text) {
    toast(this, text, Toast.LENGTH_SHORT);
}

public void toast(Context context, String text) {
    toast(context, text, Toast.LENGTH_SHORT);
}

public void toast(Context context, String text, int time) {
    Toast.makeText(context, text, time).show();
}

toast("弹个吐司");
toast(this, "弹个吐司");
toast(this, "弹个吐司", Toast.LENGTH_LONG);

그러나 위의 코 틀린에, 우리는 강력 할 필요가 없습니다, 위의 방법으로 매개 변수의 기본값에서 직접 정의 할 수 있습니다

fun toast(context : Context = this, text : String, time : Int = Toast.LENGTH_SHORT) {
    Toast.makeText(context, text, time).show()
}

toast(text = "弹个吐司")
toast(this, "弹个吐司")
toast(this, "弹个吐司", Toast.LENGTH_LONG)

확장 클래스 메소드

이 방법은, 예를 들어, 원래 클래스를 확장 할 수 상속을 사용하지 않고 문자열 클래스 방법을 확장

fun String.handle() : String {
    return this + "Android轮子哥"
}

// 需要注意,handle 方法在哪个类中被定义,这种扩展只能在那个类里面才能使用
print("HJQ = ".handle())

HJQ = Android轮子哥

연산자 오버로딩

방법이 이러한 연산자를 지원함으로써 우리는이 객체를 다시 작성할 수 있도록 코 틀린는 또한 호출되는 객체 메소드에 해당하는 최종 운영자에 사용이 더 이상 데모 코드입니다

운영자 메소드를 호출
+ A a.unaryPlus ()
-에이 a.unaryMinus ()
!에이 a.not ()

운영자 메소드를 호출
++ a.inc ()
에이-- a.dec ()

운영자 메소드를 호출
A + B a.plus (b)
A - B a.minus (b)
A * B를 a.times (b)
A / B a.div (b)
%의 B a.rem (b) a.mod (b) (중단됨)
a..b a.rangeTo (b)

운영자 메소드를 호출
B에서 b.contains (a)
! B의 ! b.contains (A)

운영자 메소드를 호출
일체 포함] a.get (I)
A [I, J] a.get (I, J)
A [i_1, ..., 2051-N] a.get (i_1, ..., 2051-N)
A [내가] = B를 a.set (I, b)
A [내가 J]를 B를 = a.set (I, J, B)
A [i_1, ..., 2051-N = B a.set (i_1, ..., 2051-N, b)

운영자 메소드를 호출
에이() a.invoke ()
일체 포함) a.invoke (I)
A (I, J) a.invoke (I, J)
A (i_1, ..., 2051-N) a.invoke (i_1, ..., 2051-N)

운영자 메소드를 호출
A + B = a.plusAssign (b)
A - B = a.minusAssign (b)
A * B = a.timesAssign (b)
A / B = a.divAssign (b)
% = B a.remAssign (b) a.modAssign (b) (중단됨)

운영자 메소드를 호출
== B를 ?를 .equals (b) : (b === NULL)
! = B ! (?를 .equals (B) : (나 === 널 (null)))

운영자 메소드를 호출
A> B a.compareTo (b)> 0
은 <B a.compareTo (b) <0
A> B = a.compareTo (b)> = 0
은 <= B를 a.compareTo (b) <= 0

확산 기능

코 틀린 확산 기능이 실행과 함께 할 몇 가지 코드를 작성하는 간단하게 생성된다, 또한, 5 개 가지 기능을 적용

  • 기능을 할 수

기능 블록 그것에 의해 오브젝트를 참조 할 수있다. 펑션 블록이 지정된 행의 반환 값 또는 마지막 복귀 식

일반 문구

fun main() {
    val text = "Android轮子哥"
    println(text.length)
    val result = 1000
    println(result)
}

표현하자

fun main() {
    val result = "Android轮子哥".let {
        println(it.length)
        1000
    }
    println(result)
}

가장 일반적인 시나리오는 null 객체에 필요한하자 기능 처리를 사용하는 것입니다 선고 통합 않는 빈 처리

mVideoPlayer?.setVideoView(activity.course_video_view)
mVideoPlayer?.setControllerView(activity.course_video_controller_view)
mVideoPlayer?.setCurtainView(activity.course_video_curtain_view)

mVideoPlayer?.let {
   it.setVideoView(activity.course_video_view)
   it.setControllerView(activity.course_video_controller_view)
   it.setCurtainView(activity.course_video_curtain_view)
}

또는 특정 범위의 범위 내에서 사용될 수있는 변수를 정의 할 필요가있다

  • 기능

이 확장 된 형태로 존재하지 않기 때문에 일부 기능은, 상술 한 실시 예는 약간 다르다 사용한다. 그것은이 오브젝트가 참조 할 수 펑션 블록의 변수 등의 목적으로한다. 펑션 블록이 지정된 행의 반환 값 또는 마지막 복귀 식

Person 클래스의 정의

class Person(var name : String, var age : Int)

일반 문구

fun main() {
    var person = Person("Android轮子哥", 100)
    println(person.name + person.age)
    var result = 1000
    println(result)
}

쓰기와

fun main() {
    var result = with(Person("Android轮子哥", 100)) {
        println(name + age)
        1000
    }
    println(result)
}

适用于调用同一个类的多个方法时,可以省去类名重复,直接调用类的方法即可,经常用于Android中RecyclerView中onBinderViewHolder中,数据model的属性映射到UI上

override fun onBindViewHolder(holder: ViewHolder, position: Int){
    val item = getItem(position)?: return
    holder.nameView.text = "姓名:${item.name}"
    holder.ageView.text = "年龄:${item.age}"
}

override fun onBindViewHolder(holder: ViewHolder, position: Int){
    val item = getItem(position)?: return
    with(item){
        holder.nameView.text = "姓名:$name"
        holder.ageView.text = "年龄:$age"
    }
}
  • run 函数

实际上可以说是let和with两个函数的结合体,run函数只接收一个lambda函数为参数,以闭包形式返回,返回值为最后一行的值或者指定的return的表达式

一般写法

var person = Person("Android轮子哥", 100)
println(person.name + "+" + person.age)
var result = 1000
println(result)

run 写法

var person = Person("Android轮子哥", 100)
var result = person.run {
    println("$name + $age")
    1000
}
println(result)

适用于let,with函数任何场景。因为run函数是let,with两个函数结合体,准确来说它弥补了let函数在函数体内必须使用it参数替代对象,在run函数中可以像with函数一样可以省略,直接访问实例的公有属性和方法,另一方面它弥补了with函数传入对象判空问题,在run函数中可以像let函数一样做判空处理,这里还是借助 onBindViewHolder 案例进行简化

override fun onBindViewHolder(holder: ViewHolder, position: Int){
    val item = getItem(position)?: return
    holder.nameView.text = "姓名:${item.name}"
    holder.ageView.text = "年龄:${item.age}"
}

override fun onBindViewHolder(holder: ViewHolder, position: Int){
    val item = getItem(position)?: return
    item?.run {
        holder.nameView.text = "姓名:$name"
        holder.ageView.text = "年龄:$age"
    }
}
  • apply 函数

从结构上来看apply函数和run函数很像,唯一不同点就是它们各自返回的值不一样,run函数是以闭包形式返回最后一行代码的值,而apply函数的返回的是传入对象的本身

一般写法

val person = Person("Android轮子哥", 100)
person.name = "HJQ"
person.age = 50

apply 写法

val person = Person("Android轮子哥", 100).apply {
    name = "HJQ"
    age = 50
}

整体作用功能和run函数很像,唯一不同点就是它返回的值是对象本身,而run函数是一个闭包形式返回,返回的是最后一行的值。正是基于这一点差异它的适用场景稍微与run函数有点不一样。apply一般用于一个对象实例初始化的时候,需要对对象中的属性进行赋值。或者动态inflate出一个XML的View的时候需要给View绑定数据也会用到,这种情景非常常见。特别是在我们开发中会有一些数据model向View model转化实例化的过程中需要用到

mRootView = View.inflate(activity, R.layout.example_view, null)
mRootView.tv_cancel.paint.isFakeBoldText = true
mRootView.tv_confirm.paint.isFakeBoldText = true
mRootView.seek_bar.max = 10
mRootView.seek_bar.progress = 0

使用 apply 函数后的代码是这样的

mRootView = View.inflate(activity, R.layout.example_view, null).apply {
   tv_cancel.paint.isFakeBoldText = true
   tv_confirm.paint.isFakeBoldText = true
   seek_bar.max = 10
   seek_bar.progress = 0
}

多层级判空问题

if (mSectionMetaData == null || mSectionMetaData.questionnaire == null || mSectionMetaData.section == null) {
    return;
}
if (mSectionMetaData.questionnaire.userProject != null) {
    renderAnalysis();
    return;
}
if (mSectionMetaData.section != null && !mSectionMetaData.section.sectionArticles.isEmpty()) {
    fetchQuestionData();
    return;
}

kotlin的apply函数优化

mSectionMetaData?.apply {

    //mSectionMetaData不为空的时候操作mSectionMetaData

}?.questionnaire?.apply {

    //questionnaire不为空的时候操作questionnaire

}?.section?.apply {

    //section不为空的时候操作section

}?.sectionArticle?.apply {

    //sectionArticle不为空的时候操作sectionArticle

}
  • also 函数

also函数的结构实际上和let很像唯一的区别就是返回值的不一样,let是以闭包的形式返回,返回函数体内最后一行的值,如果最后一行为空就返回一个Unit类型的默认值。而also函数返回的则是传入对象的本身

fun main() {
    val result = "Android轮子哥".let {
        println(it.length)
        1000
    }
    println(result) // 打印:1000
}

fun main() {
    val result = "Android轮子哥".also {
        println(it.length)
    }
    println(result) // 打印:Android轮子哥
}

适用于let函数的任何场景,also函数和let很像,只是唯一的不同点就是let函数最后的返回值是最后一行的返回值而also函数的返回值是返回当前的这个对象。一般可用于多个扩展函数链式调用

  • 总结

通过以上几种函数的介绍,可以很方便优化kotlin中代码编写,整体看起来几个函数的作用很相似,但是各自又存在着不同。使用的场景有相同的地方比如run函数就是let和with的结合体

协程

子任务协作运行,优雅的处理异步问题解决方案

协程实际上就是极大程度的复用线程,通过让线程满载运行,达到最大程度的利用CPU,进而提升应用性能

在当前 app module 中配置环境和依赖(因为现在协程在 Kotlin 中是实验性的)

kotlin {
    experimental {
        coroutines 'enable'
    }
}

dependencies {
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.20'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:0.20'
}

协程的三种启动方式

runBlocking:T     

launch:Job

async/await:Deferred
  • runBlocking

runBlocking 的中文翻译:运行阻塞。说太多没用,直接用代码测试一下

println("测试是否为主线程" + (Thread.currentThread() == Looper.getMainLooper().thread))
println("测试开始")
runBlocking {
    println("测试是否为主线程" + (Thread.currentThread() == Looper.getMainLooper().thread))
    println("测试延迟开始")
    delay(20000) // 因为 Activity 最长响应时间为 15 秒
    println("测试延迟结束")
}
println("测试结束")

17:02:08.686 System.out: 测试是否为主线程true
17:02:08.686 System.out: 测试开始
17:02:08.688 System.out: 测试是否为主线程true
17:02:08.688 System.out: 测试延迟开始
17:02:28.692 System.out: 测试延迟结束
17:02:28.693 System.out: 测试结束

runBlocking 运行在主线程,过程中 App 出现过无响应提示,由此可见 runBlocking 和它的名称一样,真的会阻塞当前的线程,只有等 runBlocking 里面的代码执行完了才会执行 runBlocking 外面的代码

  • launch

launch 的中文翻译:启动。甭管这是啥,直接用代码测试

println("测试是否为主线程" + (Thread.currentThread() == Looper.getMainLooper().thread))
println("测试开始")
launch {
    println("测试是否为主线程" + (Thread.currentThread() == Looper.getMainLooper().thread))
    println("测试延迟开始")
    delay(20000)
    println("测试延迟结束")
}
println("测试结束")

17:19:17.190 System.out: 测试是否为主线程true
17:19:17.190 System.out: 测试开始
17:19:17.202 System.out: 测试结束
17:19:17.203 System.out: 测试是否为主线程false
17:19:17.203 System.out: 测试延迟开始
17:19:37.223 System.out: 测试延迟结束
  • async

async 的中文翻译:异步。还是老套路,直接上代码

测试的时候是主线程,但是到了 launch 中就会变成子线程,这种效果类似 new Thread(),有木有?和 runBlocking 最不同的是 launch 没有执行顺序这个概念

println("测试是否为主线程" + (Thread.currentThread() == Looper.getMainLooper().thread))
println("测试开始")
async {
    println("测试是否为主线程" + (Thread.currentThread() == Looper.getMainLooper().thread))
    println("测试延迟开始")
    delay(20000)
    println("测试延迟结束")
}
println("测试结束")

17:29:00.694 System.out: 测试是否为主线程true
17:29:00.694 System.out: 测试开始
17:29:00.697 System.out: 测试结束
17:29:00.697 System.out: 测试是否为主线程false
17:29:00.697 System.out: 测试延迟开始
17:29:20.707 System.out: 测试延迟结束

这结果不是跟 launch 一样么?那么这两个到底有什么区别呢?,让我们先看一段测试代码

println("测试是否为主线程" + (Thread.currentThread() == Looper.getMainLooper().thread))
println("测试开始")
val async = async {
    println("测试是否为主线程" + (Thread.currentThread() == Looper.getMainLooper().thread))
    println("测试延迟开始")
    delay(20000)
    println("测试延迟结束")
    return@async "666666"
}
println("测试结束")

runBlocking {
    println("测试返回值:" + async.await())
}

17:50:57.117 System.out: 测试是否为主线程true
17:50:57.117 System.out: 测试开始
17:50:57.120 System.out: 测试结束
17:50:57.120 System.out: 测试是否为主线程false
17:50:57.120 System.out: 测试延迟开始
17:51:17.131 System.out: 测试延迟结束
17:51:17.133 System.out: 测试返回值:666666

看到这里你是否懂了,async 和 launch 还是有区别的,async 可以有返回值,通过它的 await 方法进行获取,需要注意的是这个方法只能在协程的操作符中才能调用

  • 线程调度

啥?协程有类似 RxJava 线程调度?先用 launch 试验一下

println("测试是否为主线程" + (Thread.currentThread() == Looper.getMainLooper().thread))
println("测试开始")
launch(CommonPool) { // 同学们,敲重点
    println("测试是否为主线程" + (Thread.currentThread() == Looper.getMainLooper().thread))
    println("测试延迟开始")
    delay(20000)
    println("测试延迟结束")
}
println("测试结束")

18:00:23.243 System.out: 测试是否为主线程true
18:00:23.244 System.out: 测试开始
18:00:23.246 System.out: 测试结束
18:00:23.246 System.out: 测试是否为主线程false
18:00:23.247 System.out: 测试延迟开始
18:00:43.256 System.out: 测试延迟结束

你:你怕不是在逗我?这个跟刚刚的代码有什么不一样吗?

我:当然不一样,假如一个网络请求框架维护了一个线程池,一个图片加载框架也维护了一个线程池.......,你会发现其实这样不好的地方在于,这些线程池里面的线程没有被重复利用,于是乎协程主动维护了一个公共的线程池 CommonPool,很好的解决了这个问题

你:你说得很有道理,还有刚刚不是说能线程调度吗?为什么还是在子线程运行?

我:因为我刚刚只用了 CommonPool 这个关键字,我再介绍另一个关键字 UI,光听名字就知道是啥了

println("测试是否为主线程" + (Thread.currentThread() == Looper.getMainLooper().thread))
println("测试开始")
launch(UI) {
    println("测试是否为主线程" + (Thread.currentThread() == Looper.getMainLooper().thread))
    println("测试延迟开始")
    delay(20000)
    println("测试延迟结束")
}
println("测试结束")

18:07:20.181 System.out: 测试是否为主线程true
18:07:20.181 System.out: 测试开始
18:07:20.186 System.out: 测试结束
18:07:20.192 System.out: 测试是否为主线程true
18:07:20.192 System.out: 测试延迟开始
18:07:40.214 System.out: 测试延迟结束


转载自:https://www.jianshu.com/p/884ca0a49e5e

추천

출처blog.csdn.net/P876643136/article/details/90125413