kotlin 学习笔记二(常见使用技巧)

1,扩展类

扩展类,就是在现有类的基础上,添加一些属性或者方法,当然扩展的这些成员需要导入当前扩展成员所在的包才可以访问到。可以不用实现装饰着模式。

data class Coordinate(val x: Double, val y: Double)

val Coordinate.theta: Double
    get() {
        return Math.atan(y/x)
    }

fun Coordinate.R():Double{
    return Math.hypot(x, y)
}

这样调用:

val coord = Coordinate(3.0,4.0)
    println(coord.theta)
    println(coord.R())

那么这个扩展有什么限制呢?

  • 在扩展成员当中,只能访问被扩展类在当前作用域内可见的成员,本例中的x和y都是public的(Kotlin默认public,这个我们后面会提到),所以可以在扩展方法和属性中直接访问。

  • 扩展成员与被扩展类的内部成员名称相同时,扩展成员将无法被访问到

 Java中会自定义一些LogUtils类来打日志,或者直接用android.util.log来输出日志。同时在相应的地方都有写TAG或者饮用静态常量。在kotlin中这样可以实现:

package com.netring.edz.kartuapplication.utils

import android.util.Log

class LogUtils {
    inline fun <reified T> T.debug(log: Any){
        Log.d(T::class.simpleName,log.toString())
    }
}

//有了这个方法,你可以在任何类的方法体中 debugLog("ss")
 inline fun <reified T> T.debugLog(log: Any){
    Log.d(T::class.simpleName,log.toString())
}

Kotlin关键字一览表(https://blog.csdn.net/sinat_23328795/article/details/78956919 )

我们就很容易看到Kotlin的标准库提供的类似with和apply这样的方法是怎么工作的了:

public inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()

public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }

我们通常会在某个方法体内创建一个对象并返回它,可我们除了调用它的构造方法之外还需要做一些其他的操作,于是就要创建一个局部变量。。。有了apply这个扩展方法,我们就可以这么写:

fun getStringBuilder: StringBuilder{
    return StringBuilder().apply{
        append("whatever")
    }
}

这样返回的StringBuilder对象实际上是包含"whatever"这个字符串的。

还有就是Fragment的创建实例生成便是用的 apply:

@JvmStatic
fun newInstance(param1: String, param2: String) =
        HomeFragment().apply {
            arguments = Bundle().apply {
                putString(ARG_PARAM1, param1)
                putString(ARG_PARAM2, param2)
            }
        }

2,函数式支持(Lambdas)

常见的Android中的点击事件

textView.setOnClickListener(new OnClickListener(){
    @Override
    public void onClick(View view){
        //todo
    }
});

kotlin中这样:

textView.setOnClickListener{ /*todo*/ }

 3,UI线程和非UI线程的切换问题。也许你会用handler不断的post。

原来在java当中,我们这么写:

handler.post(new Runnable(){
    @Override
    public void run(){
        //todo    
    }
});

MainActivity.this.runOnUiThread(
    public void run(){
        //todo
    }
});

而在Kotlin当中呢,我们只需要这么写:

async() {
    //do something asynchronously
    uiThread {
        //do something on UI thread
    }
}

详细例子:

主线程是负责UI呈现和交互的,我们不应该因其它运行时间长的任务阻塞它,这将会影响UI性能。在HTTP请求情况下, Android SDK甚至通过抛出一个异常来阻止我们这么做。在Android典型的解决方案是使用AsyncTaskAsyncTask有一个doInBackground抽象方法,其在另个线程中执行。

除了让AsyncTask正常工作很难这一事实外,由于它自身带来了许多问题,使得通过它扩展创建一个新类、在onDestroy中终止它等等,都是很乏味。这个(你可能需要更多的检查以避免崩溃)非常简单的版本将是:

 1 @Override protected void onCreate(Bundle savedInstanceState) {
 2     super.onCreate(savedInstanceState);
 3  
 4     task = new AsyncTask<Void, Void, String>() {
 5         @Override protected String doInBackground(Void... params) {
 6             return requestFromServer("<api call>");
 7         }
 8  
 9         @Override protected void onPostExecute(String s) {
10             if (!isFinishing() && !isCancelled()) {
11                 Log.d("Request", s);
12                 Toast.makeText(ExampleActivity.this, "Request performed", Toast.LENGTH_LONG).show();
13             }
14         }
15     };
16 }
17  
18 @Override protected void onDestroy() {
19     super.onDestroy();
20  
21     if (task != null) {
22         task.cancel(true);
23         task = null;
24     }
25 }

这实在不清晰也不直观。当我们在Android中用Kotlin开发时,我们不能忘记Anko库。它主要目的是提供DSL方式用代码来创建布局,而不是用XML。我实际使用过XML,所以我现在不使用它了,但是它还是包括一整套非常有用的特性。特别对异步任务有些小的DSL。这样在Kotlin中,前面的代码能够减少为:

1 async {
2     val result = URL("<api call>").readText()
3     uiThread { 
4         Log.d("Request", result)
5         longToast("Request performed") 
6     }
7 }

实际上,你有async函数,它将在另一个线程中执行代码,并由uiThread给出返回主线的机会。asyncContext的扩展函数实现,且使用它弱应用,所以不会阻止GC释放内存。

uiThread优势的方面是它依据使用类,以用不同的方式来实现。如果我们从Activity中调用它,假设actiivity.isFinishing()返回trueuiThread代码是不会执行的,并且在此情况下不会崩溃。

假设你要用future,Async返回Java Future。如果你需要返回future结果,就可以用asyncResult

 4,对象声明

单例模式在一些场景中很有用, 而 Kotlin(继 Scala 之后)使单例声明变得很容易:

有时候,我们需要创建一个对某个类做了轻微改动的类的对象,而不用为之显式声明新的子类。 Java 用匿名内部类处理这种情况。 Kotlin 用对象表达式对象声明对这个概念稍微概括了下。

object DataProviderManager {
fun registerDataProvider(provider: DataProvider) {
// ……
}
val allDataProviders: Collection<DataProvider>
get() = // ……
}

这称为对象声明。并且它总是在 object 关键字后跟一个名称。 就像变量声明一样,对象声明不是一个表达式,不能用在赋值语句的右边。

对象声明的初始化过程是线程安全的。

如需引用该对象,我们直接使用其名称即可:

DataProviderManager.registerDataProvider(……)

这些对象可以有超类型:

object DefaultListener : MouseAdapter() {
    override fun mouseClicked(e: MouseEvent) { …… }
    override fun mouseEntered(e: MouseEvent) { …… }
}

注意:对象声明不能在局部作用域(即直接嵌套在函数内部),但是它们可以嵌套到其他对象声明或非内部类中。

发布了74 篇原创文章 · 获赞 36 · 访问量 25万+

猜你喜欢

转载自blog.csdn.net/kdsde/article/details/89705753