2017-06-21 79 views
1

當我將表單kotlinx.android.synthetic.main.<layout-name>.view.*的導入添加到Kotlin源代碼中時,它會改變Android Studio編輯器的行爲。具體而言,它現在認爲View類型的任何屬性都具有與分配了ID的佈局文件中的每個視圖相對應的屬性。我假設我在而不是ActivityFragment這樣的課程中這樣做。Kotlin Android擴展視圖背後的編輯魔法是什麼?

例如,假設我在源文件中聲明瞭一個ViewHolder,並且我向其添加了一個名爲x的屬性,其類型爲View。此外,假設我有一個名爲item_test的佈局,其中有三個視圖聲明已分配了ID,a,bc。當我添加一個佈局名稱item_test突然x具有三個新的屬性,a,b,c上述表格的合成輸入。或者,更正確地說,編輯器使其看起來好像x具有這些屬性。

經過一番研究,我得出以下結論:

  • 添加布局視圖的id作爲屬性是盲目進行。任何由此類合成導入暗示的視圖ID都將添加到類型爲View(或View的子類)的任何屬性。這包括由類繼承的這種類型的屬性。

  • 由於盲目添加屬性,開發人員有義務確保在合成屬性被訪問之前分配對應於合成導入的運行時視圖,否則將拋出異常。

  • 如果在一個文件中指定了兩個或多個這樣的導入,那麼他們的視圖id的聯合將被盲目地添加到類型爲View的所有類屬性。

  • 允許多次導入的目的是解釋一個佈局文件包含另一個佈局文件的情況。

這些結論是否正確?

實現此功能還有其他有趣的細微之處嗎?

我正在使用kotlin-gradle-plugin的1.1.2-5版本。

回答

1

如果我理解正確的,我們假定你是以下幾點:

import kotlinx.android.synthetic.main.activity_main.item_test 
import kotlinx.android.synthetic.main.activity_main.item_test_2 

class MyClass { 
    lateinit var x: View 
    lateinit var y: View 

    fun foo() { 
    val foo1 = x.item_test // Compiles 
    val foo2 = y.item_test // Compiles as well 

    val bar1 = x.item_test_2 // Compiles too 
    val bar2 = y.item_test_2 // Compiles yet again 
    } 
} 

所以,在我看來,這是類型查看任何屬性將有一個合成導入相關的綜合性能,無論是否它是否有效。因此,擴展實現看起來是蠻力的,如果有什麼錯誤的話,不會提醒開發人員。

這是正確的。現在
,所述item_test進口基本上在View類的擴展屬性(簡化的示例[1]):

val View.item_test get() = findViewById(R.id.item_test) 

對於每個在佈局的意見,該插件生成這些特性,並提出他們在他們的相關文件中。這些屬性也存在於ActivityFragment
因此,當您撥打x.item_test時,您基本上呼叫x.findViewById(R.id.item_test)[1]
編譯後,插件將這些調用替換回findViewById。所以上面的方案的簡化的反編譯版本[1](在Java中):

final class MyClass { 
    public View x; 
    public View y; 

    public final void foo() { 
     TextView foo1 = (TextView) x.findViewById(id.item_test); 
     TextView foo2 = (TextView) y.findViewById(id.item_test); 
     TextView bar1 = (TextView) x.findViewById(id.item_test_2); 
     TextView bar2 = (TextView) y.findViewById(id.item_test_2); 
    } 
} 

由於這只是上View一個擴展函數時,不存在完整性檢查,以檢查是否存在於視圖層次item_testxy,就像他們不存在findViewById一樣。如果findViewById呼叫返回null,則值爲nullKotlinNullPointerException被引發。


  • 加法佈局視圖id的作爲屬性被盲目地進行。任何由這樣的綜合導入暗示的視圖id都被添加到View類型的任何屬性(或View的子類)中。這包括由類繼承的這種類型的屬性。

是,由於屬性是基於View一個擴展特性,如上所述。

  • 由於屬性被盲目地加入它是在所述顯影劑有責任確保相應於合成進口運行時視圖被訪問的合成屬性之前或分配一個異常將被拋出。

我不確定你在問什麼。如果你的意思是你在調用x.item_test之前必須初始化x,那就對了。另外,x的層次結構中應該有一個視圖item_test

  • 如果在一個文件中指定了兩個或多個這樣的導入,那麼它們的view id的聯合會被盲目地添加到View類型的所有類屬性中。 允許多次導入的目的是解釋一個佈局文件包含另一個佈局文件的情況。

是的。


[1]:其實,在幕後這些查找被緩存。請參閱文檔中的Under the hood

+0

@roobyroo我對你的問題作了另一種解釋,這是否更好? – nhaarman

+0

我已經按照承諾回覆了這個問題。 – roobyroo

+0

@roobyroo請參閱答案的補充。 – nhaarman