kotlin 接口和抽象类

抽象类可以有构造函数。接口不能有构造函数。两者都无法形成对象。 <br/> <br/>如果有很多方法,请使用interface。 <br/> <br/>接口委托是使用另一个类的对象而不是从它们继承的技术。

interface.kt
abstract class AquariumFish         // Abstract Declaration
    {
        abstract val color: String
    }
    
// Interface Declaration

interface class FishAction
    {
        fun eat()
    }
    

class Shark : AquariumFish() ,FishAction        // Inheritance
    {
        override val color = "gray"
        override fun eat()
            {
                println("\n I am eating.")
            }
    }
    

kotlin 下载xml

download xml
private fun downloadXML(urlPath: String?):String{
        val xmlResult = StringBuilder()

        try{
            val url = URL(urlPath)
            val connection : HttpsURLConnection = url.openConnection() as HttpsURLConnection
            val response = connection.responseCode

            Log.d(TAG, "downloadXML: the response code was $response")

            val inputStream = connection.inputStream
            val inputStreamReader = InputStreamReader(inputStream)
            val reader = BufferedReader(inputStreamReader)
        } catch (e: MalformedURLException){
            Log.e(TAG, "download XML: Invalid URL ${e.message}")
        } catch (e: IOException){
            Log.e(TAG, "download XML: IO exception reading data ${e.message}")
        } catch (e: Exception){
            Log.e(TAG, "Unknown exception ${e.message}")
        }
    }

kotlin ItemDedcoration

item_decoration
class MarginItemDecoration(private val spaceHeight: Int) : RecyclerView.ItemDecoration() {
    override fun getItemOffsets(outRect: Rect, view: View, 
        parent: RecyclerView, state: RecyclerView.State) {
        with(outRect) {
            if (parent.getChildAdapterPosition(view) == 0) {
                top = spaceHeight
            }
            left =  spaceHeight
            right = spaceHeight
            bottom = spaceHeight
        }
    }
}

kotlin 懒惰的启蒙

lazy initiation
private val displayOperation by lazy(LazyThreadSafetyMode.NONE) { findViewById<TextView>(R.id.operation) }

kotlin 导入小部件

import widget
import kotlinx.android.synthetic.main.activity_main.*

kotlin 计算器

calculator
package wahyuros.android.calculator

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import java.lang.NumberFormatException

#Import layout widget so we dont need to call findViewbyId
import kotlinx.android.synthetic.main.activity_main.*

private const val STATE_PENDING_OPERATION = "PendingOperation"
private const val STATE_OPERAND1 = "Operand1"
private const val STATE_OPERAND1_STORED = "Operand1_Stored"


class MainActivity : AppCompatActivity() {
    //Variable to hold operand and type of the calculation
    private var operand1: Double? = null
    private var pendingOperation = "="

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val listener = View.OnClickListener { v ->
            val b = v as Button
            newNumber.append(b.text)
        }

        button0.setOnClickListener(listener)
        button1.setOnClickListener(listener)
        button2.setOnClickListener(listener)
        button3.setOnClickListener(listener)
        button4.setOnClickListener(listener)
        button5.setOnClickListener(listener)
        button6.setOnClickListener(listener)
        button7.setOnClickListener(listener)
        button8.setOnClickListener(listener)
        button9.setOnClickListener(listener)
        buttonDot.setOnClickListener(listener)

        val opListener = View.OnClickListener { v ->
            val op = (v as Button).text.toString()
            try {
                val value = newNumber.text.toString().toDouble()
                performOperation(value, op)
            } catch (e: NumberFormatException) {
                newNumber.setText("")
            }
            pendingOperation = op
            operation.text = pendingOperation
        }

        buttonEquals.setOnClickListener(opListener)
        buttonDivide.setOnClickListener(opListener)
        buttonMultiply.setOnClickListener(opListener)
        buttonMinus.setOnClickListener(opListener)
        buttonPlus.setOnClickListener(opListener)
    }

    private fun performOperation(value: Double, operation: String) {
        if (operand1 == null) {
            operand1 = value
        } else {
            if (pendingOperation == "=") {
                pendingOperation = operation
            }

            when (pendingOperation) {
                "=" -> operand1 = value
                "/" -> operand1 = if (value == 0.0) {
                    Double.NaN
                } else {
                    operand1!! / value
                }
                "*" -> operand1 = operand1!! * value
                "+" -> operand1 = operand1!! + value
                "-" -> operand1 = operand1!! - value
            }
        }
        result.setText(operand1.toString())
        newNumber.setText("")
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        if (operand1 != null){
            outState.putDouble(STATE_OPERAND1, operand1!!)
            outState.putBoolean(STATE_OPERAND1_STORED, true)
        }
        outState.putString(STATE_PENDING_OPERATION, pendingOperation)
    }

    override fun onRestoreInstanceState(savedInstanceState: Bundle) {
        super.onRestoreInstanceState(savedInstanceState)
        operand1 = if (savedInstanceState.getBoolean(STATE_OPERAND1_STORED,false)){
            savedInstanceState.getDouble(STATE_OPERAND1)
        } else {
            null
        }
        pendingOperation = savedInstanceState.getString(STATE_PENDING_OPERATION)
        operation.text = pendingOperation
    }

}

kotlin 片段或活动的ViewModel的SavedStateHandle。

SavedStateHandle允许ViewModel访问相关Fragment或Activity的已保存状态和参数。

example
// UserProfileViewModel
class UserProfileViewModel(
   savedStateHandle: SavedStateHandle
) : ViewModel() {
   val userId : String = savedStateHandle["uid"] ?:
          throw IllegalArgumentException("missing user id")
   val user : User = TODO()
}

 // To use the viewModels() extension function, include
   // "androidx.fragment:fragment-ktx:latest-version" in your app
   // module's build.gradle file.
// UserProfileFragment
private val viewModel: UserProfileViewModel by viewModels(
   factoryProducer = { SavedStateVMFactory(this) }
   ...
)

kotlin PropertyDelegation2.kt

PropertyDelegation2.kt
/**
 * 위임 프로퍼티가 유용하게 사용되는 몇 가지 기능
 *
 * by Lazy()
 *
 * '지연 초기화(Lazy Initialization)'는 프로퍼티의 초기화를 객체를 생성할 때 하지 않고
 * 필요할 때 초기화하는 패턴이다.
 *
 * 예를 들어 객체 생성시 서버에 연결하고, 연결이 완료되면 데이터를 수신해서
 * 프로퍼티에 값을 넣는 경우
 *
 */

data class Address(val name: String, var phone: String, var addr: String = "")

fun loadAddrBook(p: Person): List<Address> {
    return listOf()
}

open class Person(open val name: String) {
    private var _addrBook: List<Address>? = null
    open val addrBook: List<Address>
        get() {
            if (_addrBook == null) _addrBook = loadAddrBook(this)
            return _addrBook!! // absolutely, I'm not null
        }
}

/**
 * 위에 소스코드는 일반적인 Lazy코드의 작성법이다. 근데 또 너무 길어서 코틀린에서는
 * 간단한 방법을 제공해줌
 */

class Person2(override val name: String) : Person(name) {
    override val addrBook by lazy({ loadAddrBook(this) })
    /**
     * lazy() 메서드에는 몇 가지 제약사항이 있는데
     * var 타입의 프로퍼티에는 사용할 수 없다는 것
     * (최초에 한 번만 초기화되므로 변경 될 수 없다)
     */
}

fun main(args: Array<String>?) {

}

kotlin 코틀린프로퍼티위임(委托财产)

코틀린프로퍼티위임(委托财产)

PropertyDelegation.kt
import kotlin.reflect.KProperty

/**
 * 위임 프로퍼티란
 *
 * 프로퍼티 필드에 접근하는 접근자 로직을 다른 객체에 맡기는 방식을 말한다.
 * 즉, 게터와 세터 메서드를 가지는 다른 객체를 만들어서 그 객채에 프로퍼티의 플드 접근로직을 위임하는 것.
 */

fun main(args: Array<String>) : Unit {
    /**
     * 예, Person이라는 클래스를 만들고 클래스의 프로퍼티 값이 변경되거나 읽어올 때마다 메세지를 발생시키는 기능을 넣고 싶다.
     */
    class Person(val name: String, val _age: Int, val _salary: Int) {
        var age: Int = _age
            get() {
                println("age get! $field")
                return field
            }
            set(value) {
                println("age set! $value")
                field = value
            }

        var salary: Int = _salary
            get() {
                println("salary get! $field")
                return field
            }
            set(value) {
                println("salary set! $value")
                field = value
            }
    }

    val p = Person("임원빈", 29, 2000)
    p.age = 30
    p.salary = 3000
    println("${p.name} - ${p.age} - ${p.salary}")

    /**
     * 뭔가 이상하지 이런식이라면 중복된 기능의 코드가 계속해서 증식할 것이다. 자바스크립트 처럼 callback 함수를 미리 1개 선언해 놓고
     * 필요한 이벤트리스너의 함수를 할당해주는 것 처럼 코드를 수정하면 코틀린에서 추구하는 간결함을 한 껏 살릴 수 있지 않을까 하는데..
     */
    class PropertyDelegator(val fname: String) {
        var value: Int = 0

        fun getMethod(): Int {
            println("$fname get! $value")
            return value
        }

        fun setMethod(newValue: Int) {
            println("$fname set! $newValue")
            value = newValue
        }
    }

    class Person2(val name: String) {
        val ageDelegator = PropertyDelegator("age")
        val salaryDelegator = PropertyDelegator("salary")

        var age: Int
            get() = ageDelegator.getMethod()
            set(value: Int) = ageDelegator.setMethod(value)
        var salary: Int
            get() = salaryDelegator.getMethod()
            set(value: Int) = salaryDelegator.setMethod(value)
    }

    /**
     * 이것도 뭔가 애매하다. PropertyDelegator 클래스를 따로 작성해줘야 하고..
     * 여기서 사용할 수 있는게 바로 위임(Delegation)이다.
     */
    class PropertyDelegator2(var value: Int) {
        operator fun getValue(thisRef: Any?, property: KProperty<*>): Int {
            println("${property.name} get! $value")
            return value
        }
        operator fun setValue(thisRef: Any?, property: KProperty<*>, newValue: Int) {
            value = newValue
        }
    }

    class Person3(val name: String, age: Int, salary: Int) {
        var age: Int by PropertyDelegator2(age)
        var salary: Int by PropertyDelegator2(salary)
    }

    /**
     * 위임 받을 클래스에는 getValue() 메서드와 setValue() 메서드가 구현되어 있어야 한다.
     * getValue()와 setValue() 메서드의 앞에 operator 접근자가 붙어 있는 것에 유의하자.
     *
     * 또, getValue() 메서드와 setValue() 메서드는 지정된 파라미터를 사용해야 하며,
     * 지정된 파라미터는 아래와 같다.
     */
}

kotlin 从Factory检索ViewModel

extensions.kt
inline fun <reified VM : ViewModel, T> T.viewModel(): Lazy<VM> where T : KodeinAware, T : FragmentActivity {
    return lazy { ViewModelProviders.of(this, direct.instance()).get(VM::class.java) }
}
extensions.kt
inline fun <reified VM : ViewModel, T> T.viewModel(): Lazy<VM> where T : KodeinAware, T : AppCompatActivity {
    return lazy { ViewModelProviders.of(this, direct.instance()).get(VM::class.java) }
}
extensions.kt
inline fun <reified VM : ViewModel, T> T.viewModel(): Lazy<VM> where T : KodeinAware, T : Fragment {
    return lazy { ViewModelProviders.of(this, direct.instance()).get(VM::class.java) }
}