https://kotlinlang.org/docs/reference/android-overview.html
學(xué)習(xí)資料
記錄
let, also,apply,run
https://blog.csdn.net/u013064109/article/details/78786646
簡(jiǎn)單分析下,also和apply一樣都是返回自己, let和run一樣返回花括號(hào)代碼塊最后一行的返回值
另外一樣的2種區(qū)別就在于代碼塊里用it還是this代替變量,而this可以省略不寫。

如上圖,結(jié)果就是 2個(gè)hello,以及7和5
簡(jiǎn)單看下源碼
public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
public inline fun <T> T.also(block: (T) -> Unit): T { block(this); return this }
public inline fun <T, R> T.let(block: (T) -> R): R = block(this)
public inline fun <T, R> T.run(block: T.() -> R): R = block()
看到源碼可能感覺和我們的寫法不一樣。其實(shí)原因很簡(jiǎn)單,kotlin里一個(gè)函數(shù)可以作為參數(shù)的,完事這個(gè)函數(shù)可以寫到括號(hào)外邊。
比如 T.apply({//函數(shù)塊}) 可以寫成 T.apply(){//函數(shù)塊}
對(duì)于let和run,如果要主動(dòng)return一個(gè)東西,這樣寫的// return@run 333
在看demo的時(shí)候看到這些代碼,擴(kuò)展函數(shù)
可以注意到方法名字前有個(gè)xxx. 的東西,這個(gè)就是聲明對(duì)哪個(gè)類進(jìn)行擴(kuò)展
/**
* The `fragment` is added to the container view with id `frameId`. The operation is
* performed by the `fragmentManager`.
*/
fun AppCompatActivity.replaceFragmentInActivity(fragment: Fragment, @IdRes frameId: Int) {
supportFragmentManager.transact {
replace(frameId, fragment)
}
}
/**
* The `fragment` is added to the container view with tag. The operation is
* performed by the `fragmentManager`.
*/
fun AppCompatActivity.addFragmentToActivity(fragment: Fragment, tag: String) {
supportFragmentManager.transact {
add(fragment, tag)
}
}
fun AppCompatActivity.setupActionBar(@IdRes toolbarId: Int, action: ActionBar.() -> Unit) {
setSupportActionBar(findViewById(toolbarId))
supportActionBar?.run {
action()
}
}
/**
* Runs a FragmentTransaction, then calls commit().
*/
private inline fun FragmentManager.transact(action: FragmentTransaction.() -> Unit) {
beginTransaction().apply {
action()
}.commit()
}
代碼里這樣用的
setupActionBar(R.id.toolbar) {
setHomeAsUpIndicator(R.drawable.ic_menu)
setDisplayHomeAsUpEnabled(true)
}
其實(shí)原本應(yīng)該這樣的,不過最后一個(gè)參數(shù)是一個(gè)函數(shù)的話,可以直接把括號(hào)的實(shí)現(xiàn)提到圓括號(hào)外面,就成了上邊的寫法了
setupActionBar(R.id.toolbar, {
setHomeAsUpIndicator(R.drawable.ic_menu)
setDisplayHomeAsUpEnabled(true)
})
when
java 中的switch 在kotlin里的寫法,
when(xxx){
is Int->{
}
in 0..10->{
}
1->{
}
2->{
}
3,4->{}
else->{}
}
2個(gè)方法互相引用的時(shí)候
java代碼如下,我是2個(gè)runnable 互相調(diào)用
private void starte(){
handler.postDelayed(r1,1000);
}
Handler handler=new Handler();
Runnable r1=new Runnable() {
@Override
public void run() {
System.out.println("==========1");
handler.postDelayed(r2,1111);
}
};
Runnable r2=new Runnable() {
@Override
public void run() {
System.out.println("==========2");
handler.postDelayed(r1,1111);
}
};
kotlin代碼如下
internal var handler = Handler()
internal var r1: Runnable = Runnable {
println("==========1")
handler.postDelayed(r2, 1111)
}
internal var r2: Runnable = Runnable {
println("==========2")
handler.postDelayed(r1, 1111)
}
private fun starte() {
handler.postDelayed(r1, 1000)
}
看下轉(zhuǎn)化,加了internal,這個(gè)是限定同一模塊下可以訪問,非必需。
關(guān)鍵有的地方 r2: Runnable 這個(gè),2個(gè)Runnable必須有一個(gè)需要加冒號(hào)聲明類型,否則就報(bào)錯(cuò)。
Type checking has run into a recursive problem. Easiest workaround: specify types of your declarations explicitly
中文:類型檢查遇到了遞歸問題。最簡(jiǎn)單的解決方法:顯式地指定聲明的類型。
可以看到上邊都是簡(jiǎn)化后的寫法了。如果這個(gè)時(shí)候要使用this,就不行了,得寫完整的
如下
internal var r2: Runnable = object : Runnable {
override fun run() {
println("==========2")
handler.postDelayed(r1, 1111)
handler.postDelayed(this, 2222)
Runnable { handler.postDelayed(this, 2222) }.run()
}
}
循環(huán)的幾種寫法
下邊的代碼結(jié)果都一樣,都是從0到4循環(huán)的,從大到小的話可以用 downto關(guān)鍵字
private fun forTest(){
//循環(huán)N次,from 0 start
repeat(5){
println("a============$it")
}
for(i in 0 ..4){
println("b==========$i")
}
for(i in 0 until 5){
println("c==========$i")
}
(0..4).forEach {
println("d==============$it")
}
}
set get
//set的簡(jiǎn)化寫法
var tasks: List<Task> = tasks
set(tasks) {
field = tasks
notifyDataSetChanged()
}
//get的簡(jiǎn)化寫法
override var isActive: Boolean = false
get() = isAdded
thread ,簡(jiǎn)化寫法如下,不需要start,內(nèi)部默認(rèn)構(gòu)造方法里start為true的。
thread {
}
問題記錄
1~
java 代碼 Object obj=new Object(); obj.wait();
kotlin里的Any()對(duì)象沒有wait()方法,不知道轉(zhuǎn)成kotlin之后咋寫。
解決辦法,kt里繼續(xù)new一個(gè)Object對(duì)象而不是any對(duì)象。
http://www.itdecent.cn/p/3963e64e7fe7
2~
雙冒號(hào)::
可以理解為把一個(gè)方法當(dāng)對(duì)象處理,如下
class A {
lateinit var b:B
init {
b=B().apply {
this.callbackA=this@A::testA//把testA這個(gè)方法傳遞給B里邊的一個(gè)變量callbackA了
}
}
fun testA(name: String,age:Int){
}
}
class B{
var callbackA:((String,Int) ->Unit)?=null//這里對(duì)應(yīng)寫出參數(shù)的類型,返回的類型好匹配,因?yàn)槭强梢詾榭盏?,所以括起來加個(gè)問號(hào)
fun testB(){
callbackA?.invoke("jerry",33)
}
}
上邊的可以用來寫我們平時(shí)用的Callback。
如果是java,我們一般是定義一個(gè)interface,完事定義一個(gè)interface的變量,然后用的時(shí)候?qū)嵗粋€(gè)interface調(diào)用
然后看下改版后的寫法
如下自定義的類
class ItemTouchListener{
//某個(gè)地方調(diào)用
singleTapCallback?.invoke(position,rv.getChildViewHolder(child))
//然后定義的回調(diào)
var singleTapCallback:((position: Int, viewHolder: RecyclerView.ViewHolder)->Unit)?=null
}
然后是正式使用的地方
rv_temp.addOnItemTouchListener(ItemTouchListener(rv_temp).apply {
singleTapCallback=this@FragmentTempTest::singleTab
//或者這樣調(diào)用也可以
singleTapCallback={position, viewHolder ->
}
})
//這個(gè)就是我們的回調(diào)實(shí)現(xiàn)方法拉。
fun singleTab(position: Int, viewHolder: RecyclerView.ViewHolder){
}
這里還有一些
https://blog.csdn.net/lmo28021080/article/details/81505211
inline,noline
參考https://blog.csdn.net/Jaden_hool/article/details/78437947
基本數(shù)據(jù)類型
比較坑的地方,就是不能互相自動(dòng)轉(zhuǎn)化,java里我們定義個(gè)float,傳個(gè)int也沒問題的,在kt里就不行
有點(diǎn),數(shù)字下邊可以加下劃線,看起來更直觀
val oneMillion = 1_000_000
val creditCardNumber = 1234_5678_9012_3456L
val socialSecurityNumber = 999_99_9999L
val hexBytes = 0xFF_EC_DE_5E
val bytes = 0b11010010_01101001_10010100_10010010
== === 2個(gè)等號(hào)和3個(gè)等號(hào)的區(qū)別
前者是數(shù)值比較,后者是地址比較
== 和 ===
其中這個(gè)比較嚇人
fun main(args: Array<String>) {
val a: Int = 1000
val b: Int? = a
val c: Int? = a
println(b == c) //true
println(b === c) //false
}
fun main(args: Array<String>) {
val a: Int = 100
val b: Int? = a
val c: Int? = a
println(b == c) //true
println(b === c) //true
}
兩段代碼除了a的初始值不一樣,其他都一樣,可結(jié)果3個(gè)等號(hào)的結(jié)果不一樣。
這個(gè)就是java里基本數(shù)據(jù)類型和對(duì)象的問題了,看下源碼,128以下的,用的是同一個(gè)對(duì)象,從緩存數(shù)組讀出來的,所以對(duì)象比較也是相等的,128以上的,就是每次new一個(gè)新的了,不是一個(gè)對(duì)象了。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
運(yùn)算符
這是完整的位運(yùn)算列表(只用于 Int 與 Long):
shl(bits) – 有符號(hào)左移 (Java 的 <<)
shr(bits) – 有符號(hào)右移 (Java 的 >>)
ushr(bits) – 無符號(hào)右移 (Java 的 >>>)
and(bits) – 位與
or(bits) – 位或
xor(bits) – 位異或
inv() – 位非
后綴 u 與 U 將字面值標(biāo)記為無符號(hào)
val l: ULong = 1u // ULong,已提供預(yù)期類型
val a1 = 42u // UInt:未提供預(yù)期類型,常量適于 UInt
"""
原始字符串 使用三個(gè)引號(hào)(""")分界符括起來,內(nèi)部沒有轉(zhuǎn)義并且可以包含換行以及任何其他字符:
比如下邊這個(gè),最終顯示結(jié)果有4行,第一個(gè)換行,最后一行換行的,中間的空白頁都保留的
val text = """
for (c in "foo")
print(c)
"""
when
常見的when用法,類似java里的swtich,不過比這個(gè)強(qiáng)大很多
when (x) {
parseInt(s) -> print("s encodes x")
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
is String -> x.startsWith("prefix")
else -> print("s does not encode x")
}
when 也可以用來取代 if-else if鏈。 如果不提供參數(shù),所有的分支條件都是簡(jiǎn)單的布爾表達(dá)式,而當(dāng)一個(gè)分支的條件為真時(shí)則執(zhí)行該分支:
when {
x.isOdd() -> print("x is odd")
x.isEven() -> print("x is even")
else -> print("x is funny")
}
還有這種
fun Request.getBody() =
when (val response = executeRequest()) {
is Success -> response.body
is HttpError -> throw HttpException(response.status)
}
密封類
用sealed 修飾class
sealed
for
for的特殊用法,迭代類型的可以直接拿到key和value
val arr= arrayListOf(2,3,3,33,3)
for((index,value) in arr.withIndex()){
}
標(biāo)簽lable
標(biāo)示符后邊加個(gè)@即可
loop@ for (i in 1..100) {
// ……
}
函數(shù)
主構(gòu)造函數(shù)和次構(gòu)造函數(shù),還有init的執(zhí)行順序
主構(gòu)造函數(shù)不能包含任何的代碼。初始化的代碼可以放到以 init 關(guān)鍵字作為前綴的初始化塊(initializer blocks)中。
在實(shí)例初始化期間,初始化塊按照它們出現(xiàn)在類體中的順序執(zhí)行,與屬性初始化器交織在一起:
下邊4句的結(jié)果是按順序打印的
class InitOrderDemo(name: String) {
val firstProperty = "First property: $name".also(::println)
init {
println("First initializer block that prints ${name}")
}
val secondProperty = "Second property: ${name.length}".also(::println)
init {
println("Second initializer block that prints ${name.length}")
}
}
如果類有一個(gè)主構(gòu)造函數(shù),每個(gè)次構(gòu)造函數(shù)需要委托給主構(gòu)造函數(shù), 可以直接委托或者通過別的次構(gòu)造函數(shù)間接委托。委托到同一個(gè)類的另一個(gè)構(gòu)造函數(shù)用 this 關(guān)鍵字即可:
class Person(val name: String) {
constructor(name: String, parent: Person) : this(name) {
parent.children.add(this)
}
}
初始化塊中的代碼實(shí)際上會(huì)成為主構(gòu)造函數(shù)的一部分。委托給主構(gòu)造函數(shù)會(huì)作為次構(gòu)造函數(shù)的第一條語句,因此所有初始化塊中的代碼都會(huì)在次構(gòu)造函數(shù)體之前執(zhí)行。即使該類沒有主構(gòu)造函數(shù),這種委托仍會(huì)隱式發(fā)生,并且仍會(huì)執(zhí)行初始化塊:
下邊init代碼先執(zhí)行的
class Constructors {
init {
println("Init block")
}
constructor(i: Int) {
println("Constructor")
}
}
lateinit 和by lazy
lateinit 是給var用的,而且必須給予值,頁面銷毀的時(shí)候如果沒有賦值,就掛了。
by lazy是給val用的, 后邊跟一個(gè)代碼塊,代碼塊最后一行就是返回值,并且代碼塊只會(huì)執(zhí)行一次,也就是第一次調(diào)用s這個(gè)變量的時(shí)候println會(huì)打印,再后邊調(diào)用s這個(gè)值,就不會(huì)執(zhí)行這個(gè)代碼塊了,s已經(jīng)有值了,直接返回即可。
val s:String by lazy {
println("lazy==============")
"xxxx"
}
lateinit var ss:String
覆蓋屬性
在超類中聲明然后在派生類中重新聲明的屬性必須以 override 開頭,并且它們必須具有兼容的類型。每個(gè)聲明的屬性可以由具有初始化器的屬性或者具有 getter 方法的屬性覆蓋
open class Foo {
open val x: Int get() { …… }
}
class Bar1 : Foo() {
override val x: Int = ……
}
你也可以用一個(gè) var 屬性覆蓋一個(gè) val 屬性,但反之則不行.因?yàn)橐粋€(gè) val 屬性本質(zhì)上聲明了一個(gè) getter 方法,而將其覆蓋為 var 只是在子類中額外聲明一個(gè) setter 方法。你可以在主構(gòu)造函數(shù)中使用 override 關(guān)鍵字作為屬性聲明的一部分。
interface Foo {
val count: Int
}
class Bar1(override val count: Int) : Foo
class Bar2 : Foo {
override var count: Int = 0
}
覆蓋方法
2個(gè)父類有同名的方法,子類咋調(diào)用,用尖括號(hào)聲明父類
open class A {
open fun f() { print("A") }
fun a() { print("a") }
}
interface B {
fun f() { print("B") } // 接口成員默認(rèn)就是“open”的
fun b() { print("b") }
}
class C() : A(), B {
// 編譯器要求覆蓋 f():
override fun f() {
super<A>.f() // 調(diào)用 A.f()
super<B>.f() // 調(diào)用 B.f()
}
}
擴(kuò)展函數(shù)
定義也比較簡(jiǎn)單,想擴(kuò)展哪個(gè)類,就點(diǎn)一下
class D:()
fun D.foo() = "d"
擴(kuò)展屬性
擴(kuò)展屬性不能有初始化器,他們的行為只能由顯式提供的 getters/setters 定義。
val <T> List<T>.lastIndex: Int
get() = size - 1
消費(fèi)者 in, 生產(chǎn)者 out
如下方法里的參數(shù),有個(gè)in修飾,如果用out修飾,你在方法體里邊無法修改args參數(shù)的,in可以修改
override fun invoke(proxy: Any?, method: Method, args: Array<in Any>): Any? {}
可變參數(shù)
java里省略號(hào)表示可變參數(shù),可以傳多個(gè)參數(shù),也可以傳個(gè)數(shù)組,可kotlin調(diào)用的時(shí)候咋辦?
//java里代碼如下
public native Object invoke(Object obj, Object... args)
//kotlin里我們拿到的是個(gè)數(shù)組,下邊的參數(shù)args
override fun invoke(proxy: Any?, method: Method, args: Array<in Any>)
//使用的時(shí)候如下,前邊加個(gè)星號(hào)
method.invoke(xxx,*args);