Kotin Android Extensionsの中身とこれから

Kotin Android Extensionsの中身とこれから

2017/11/09 第7回 Kotlin勉強会 @SanSan

むろほしりょうた(@RyotaMurohoshi)
の資料です。

F46c97bb74758d481531990654933050?s=128

RyotaMurohoshi

November 09, 2017
Tweet

Transcript

  1. Ko#n Android Extensionsͷத਎ͱ͜Ε͔Β @RyotaMurohoshi 2017/11/09 ୈ7ճ Kotlinษڧձ @SanSan

  2. Kotlin Android Extensions ࢖͍ͬͯΔਓʁ

  3. ΍ͬͺΓDataBindingͰ͔͢ʁ ͦΕͱ΋ankoͰ͔͢ʁ

  4. Kotlin Android Extensions ๻͸ɺ޷͖Ͱ͢

  5. ɹࣗݾ঺հ @RyotaMurohoshi

  6. ࠷ۙձࣾͰɺKotlinຊಡॻձΛ࢝Ί·ͨ͠

  7. Tools > Kotlin > Show Kotlin Bytecode > Decompile ͜ΕΛԿΑΓઌʹڭ͑ͯ͋͛Δͱ͍͍ͱࢥ͏ʂ

  8. ʮKo#n Android Extensionsͷ த਎ͱ͜Ε͔Βʯ ʹ͍ͭͯ࿩͠·͢ Kotlin 1.1.51ʹͯ

  9. Kotlin Android Extensions ʹ͍͓ͭͯ͞Β͍

  10. ViewͷΠϯελϯεʹ௒؆୯ʹ ΞΫηεͰ͖Δ΍ͭ

  11. gadleͷதͰ͜͏ॻ͘ (͍ͯ͏͔σϑΥϧτͰೖ͍ͬͯΔ) apply plugin: 'kotlin-android-extensions'

  12. <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.teammurosta.MainActivity"> <TextView

    android:id="@+id/textView" android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_centerInParent="true" /> </RelativeLayout>
  13. ίʔυͰtextViewͱ͍͏໊લͰ TextViewܕͱͯ͠ΞΫηεͰ͖Δ class MainActivity : Activity() { override fun onCreate(savedInstanceState:

    Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // TextViewܕͷtextView͕ʂ textView.text = "Hello Activity" } }
  14. // TextViewܕͷtextView͕ʂ textView.text = "Hello Activity"

  15. ؆୯Ͱ͠ΐʂ ศརͰ͠ΐʂ

  16. த਎ΈͯΈ·͠ΐ͏

  17. Tools > Kotlin > Show Kotlin Bytecode > Decompile

  18. class MainActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) {

    super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // TextViewܕͷtextView͕ʂ textView.text = "Hello Activity" } }
  19. /* ུ */ public final class MainActivity extends AppCompatActivity {

    private HashMap _$_findViewCache; protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setContentView(2131296283); ((TextView)this._$_findCachedViewById(id.textView)).setText((CharSequence)"Hello Activity"); } public View _$_findCachedViewById(int var1) { if(this._$_findViewCache == null) { this._$_findViewCache = new HashMap(); } View var2 = (View)this._$_findViewCache.get(Integer.valueOf(var1)); if(var2 == null) { var2 = this.findViewById(var1); this._$_findViewCache.put(Integer.valueOf(var1), var2); } return var2; } public void _$_clearFindViewByIdCache() { if(this._$_findViewCache != null) { this._$_findViewCache.clear(); } } }
  20. /* ུ */ public final class MainActivity extends AppCompatActivity {

    private HashMap _$_findViewCache; protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setContentView(2131296283); ((TextView)this._$_findCachedViewById(id.textView)) .setText((CharSequence)"Hello Activity"); } public View _$_findCachedViewById(int var1) { if(this._$_findViewCache == null) { this._$_findViewCache = new HashMap(); } View var2 = (View)this._$_findViewCache.get(Integer.valueOf(var1)); if(var2 == null) { var2 = this.findViewById(var1); this._$_findViewCache.put(Integer.valueOf(var1), var2); } return var2; } /* ུ */
  21. σίϯύΠϧͯ͠ΈΔͱ • _$_findViewCacheͱ͍͏HashMapΛϑΟʔϧυͱͯ࣋ͭ͠ • _$_findCachedViewByIdϝιου͸ɺ • Ҿ਺ʹͱͬͨid͕HashMapʹ͋Ε͹ͦΕΛฦ͠ • ͳ͚Ε͹୳ࡧɺHashMapʹೖΕͨޙɺͦΕΛฦ͢ _$_findViewCache΍_findCachedViewById͸ɺKotlinͰ͸ίʔυͰ͔͚ͳ͍ɻཁʮ``ʯ

  22. /* ུ */ public final class MainActivity extends AppCompatActivity {

    private HashMap _$_findViewCache; protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setContentView(2131296283); ((TextView)this._$_findCachedViewById(id.textView)) .setText((CharSequence)"Hello Activity"); } public View _$_findCachedViewById(int var1) { if(this._$_findViewCache == null) { this._$_findViewCache = new HashMap(); } View var2 = (View)this._$_findViewCache.get(Integer.valueOf(var1)); if(var2 == null) { var2 = this.findViewById(var1); this._$_findViewCache.put(Integer.valueOf(var1), var2); } return var2; } /* ུ */
  23. ͜Μͳײ͡ͷ֦ுϓϩύςΟ͕ੜ͑ΔΘ͚Ͱ͸ͳ͍ʂ // ͜Μͳײ͡͡Όͳ͍ʂ // Ωϟογϡػߏ͋ΔΑ val MainActivity.textView : TextView get()

    = findViewById(R.id.textView)
  24. FragmentͰ΋Kotlin Android Extensions࢖͑·͢ FragmentͰ΋ಉ͡Α͏ʹHashMapͰͷΩϟογϡػߏʂ

  25. ֦ுؔ਺ͷதͰ΋ʂ package com.teammurosta import kotlinx.android.synthetic.main.activity_main.* fun MainActivity.updateText(text: String) { this.textView.text

    = text }
  26. import android.os.Bundle import android.support.v7.app.AppCompatActivity class MainActivity : AppCompatActivity() { override

    fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) updateText("Hello") } }
  27. // ֦ுؔ਺ͷσίϯύΠϧ݁Ռ public final class MainActivityExtensionsKt { public static final

    void updateText(@NotNull MainActivity $receiver, @NotNull String text) { Intrinsics.checkParameterIsNotNull($receiver, "$receiver"); Intrinsics.checkParameterIsNotNull(text, "text"); ((TextView)$receiver._$_findCachedViewById(id.textView)).setText((CharSequence)text); } }
  28. // MainActivityͷσίϯύΠϧ݁Ռ public final class MainActivity extends AppCompatActivity { private

    HashMap _$_findViewCache; protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.setContentView(2131296283); MainActivityExtensionsKt.updateText(this, "Hello"); } public View _$_findCachedViewById(int var1) { if(this._$_findViewCache == null) { this._$_findViewCache = new HashMap(); } View var2 = (View)this._$_findViewCache.get(Integer.valueOf(var1)); if(var2 == null) { var2 = this.findViewById(var1); this._$_findViewCache.put(Integer.valueOf(var1), var2); } return var2; } public void _$_clearFindViewByIdCache() { if(this._$_findViewCache != null) { this._$_findViewCache.clear(); } } }
  29. Կ͕ԿͰ΋Ωϟογϡ͢ΔΘ͚͡Όͳ͍

  30. ֦ுؔ਺ͷதͰ΋ʂMainAc'vity -> Ac'vityʹมߋʂ package com.teammurosta import kotlinx.android.synthetic.main.activity_main.* fun Activity.updateText(text: String)

    { this.textView.text = text }
  31. // ֦ுؔ਺ͷσίϯύΠϧ݁Ռ public final class MainActivityExtensionsKt { public static final

    void updateText(@NotNull Activity $receiver, @NotNull String text) { Intrinsics.checkParameterIsNotNull($receiver, "$receiver"); Intrinsics.checkParameterIsNotNull(text, "text"); ((TextView)$receiver.findViewById(id.textView)).setText((CharSequence)text); } }
  32. android.app.Ac+vityΫϥε΍ android.support.v7.app.AppCompatAc2vityΫϥεɺ android.support.v4.app.FragmentΫϥεΛ֦ுͨ͠৔߹ɺ ී௨ʹfindViewByIdΛݺͿ

  33. ViewHolderͰͷ׆༻ྫ

  34. Kotlin Android Extensions Λ࢖ͬͯBind import kotlinx.android.synthetic.main.listitem_product.view.* class ProductViewHolder(containerView: View) :

    RecyclerView.ViewHolder(containerView) { fun bind(product: Product) { itemView.nameTextView.text = product.name itemView.idTextView.text = product.id } }
  35. σίϯύΠϧ݁ՌΛΈΔͱΩϟογϡ͍ͯ͠ͳ͍ public final class ProductViewHolder extends ViewHolder { public final

    void bind(@NotNull Product product) { Intrinsics.checkParameterIsNotNull(product, "product"); ((TextView)this.itemView.findViewById(id.nameTextView)).setText((CharSequence)product.getName()); ((TextView)this.itemView.findViewById(id.idTextView)).setText((CharSequence)product.getId()); } public ProductViewHolder(@NotNull View containerView) { Intrinsics.checkParameterIsNotNull(containerView, "containerView"); super(containerView); } }
  36. ͔͜͜Βઌ͸ɺ͜Ε͔Βͷ࿩

  37. Kotlin 1.1.4ͰύϫʔΞοϓ experimental͚ͩͲ androidExtensions { experimental = true }

  38. 1. Ωϟογϡઓུ

  39. @ContainerOp,ons

  40. ࠓ·ͰΩϟογϡ͸HashMapͷΈ ʮSparseArrayʯͱʮΩϟογϡ͠ͳ͍ʯ Λબ΂ΔΑ͏ʹͳͬͨʂ

  41. // ↓Ξϊςʔγϣϯ஫໨ @ContainerOptions(CacheImplementation.SPARSE_ARRAY) class MainActivity : Activity() { override fun

    onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) textView.text = "Hello" } }
  42. public final class MainActivity extends Activity { private SparseArray _$_findViewCache;

    protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); ((TextView)this._$_findCachedViewById(id.textView)).setText((CharSequence)"Hello"); } public View _$_findCachedViewById(int var1) { if(this._$_findViewCache == null) { this._$_findViewCache = new SparseArray(); } View var2 = (View)this._$_findViewCache.get(var1); if(var2 == null) { var2 = this.findViewById(var1); this._$_findViewCache.put(var1, var2); } return var2; } public void _$_clearFindViewByIdCache() { if(this._$_findViewCache != null) { this._$_findViewCache.clear(); } } }
  43. // ↓Ξϊςʔγϣϯ஫໨ @ContainerOptions(CacheImplementation.NO_CACHE) class MainActivity : Activity() { override fun

    onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) textView.text = "Hello" } }
  44. public final class MainActivity extends Activity { protected void onCreate(@Nullable

    Bundle savedInstanceState) { super.onCreate(savedInstanceState); ((TextView)this.findViewById(id.textView)).setText((CharSequence)"Hello"); } }
  45. Ұׅมߋ΋Ͱ͖Δ ະυΩϡϝϯτԽͰ࢓༷มߋ͢Δ͔΋͠Εͳ͍͚Ͳ

  46. app/build.gradle಺Ͱઃఆ androidExtensions { experimental = true defaultCacheImplementation = "sparse_array" //

    hash_map or none }
  47. ΩϟογϡʹSparseArrayɺ࢖ͬͨ΄͏͕͍͍ͷʁ

  48. Do we need to change the default cache implementa3on to

    SparseArray? Looks like no, because "It is generally slower than a tradi8onal HashMap, since lookups require a binary search and adds and removes require inser8ng and dele8ng entries in the array" Kotlin KEEPΑΓ
  49. 2. ViewHolderରԠ

  50. Kotlin Android Extensions Λ࢖ͬͯBind import kotlinx.android.synthetic.main.listitem_product.view.* class ProductViewHolder(containerView: View) :

    RecyclerView.ViewHolder(containerView) { fun bind(product: Product) { itemView.nameTextView.text = product.name itemView.idTextView.text = product.id } }
  51. σίϯύΠϧ݁ՌΛΈΔͱΩϟογϡ͍ͯ͠ͳ͍ public final class ProductViewHolder extends ViewHolder { public final

    void bind(@NotNull Product product) { Intrinsics.checkParameterIsNotNull(product, "product"); ((TextView)this.itemView.findViewById(id.nameTextView)).setText((CharSequence)product.getName()); ((TextView)this.itemView.findViewById(id.idTextView)).setText((CharSequence)product.getId()); } public ProductViewHolder(@NotNull View containerView) { Intrinsics.checkParameterIsNotNull(containerView, "containerView"); super(containerView); } }
  52. Ac#vity΍FragmentͷαϒΫϥεΈ͍ͨʹ Ωϟογϡ͢Δʹ͸ʁ

  53. LayoutContainer

  54. LayoutContainerΛ࣮૷͢Δ import kotlinx.android.synthetic.main.listitem_product.* class ProductViewHolder(override val containerView: View /*<= ஫໨

    */) : RecyclerView.ViewHolder(containerView), LayoutContainer /*<= ஫໨ */ { fun bind(product: Product) { // ஫໨ nameTextView.text = product.name idTextView.text = product.id } }
  55. Ωϟογϡ͢ΔΑ͏ʹʂ public final class ProductViewHolder extends ViewHolder implements LayoutContainer {

    @NotNull private final View containerView; private HashMap _$_findViewCache; public final void bind(@NotNull Product product) { Intrinsics.checkParameterIsNotNull(product, "product"); ((TextView)this._$_findCachedViewById(id.nameTextView)).setText((CharSequence)product.getName()); ((TextView)this._$_findCachedViewById(id.idTextView)).setText((CharSequence)product.getId()); } @NotNull public View getContainerView() { return this.containerView; } public ProductViewHolder(@NotNull View containerView) { Intrinsics.checkParameterIsNotNull(containerView, "containerView"); super(containerView); this.containerView = containerView; } public View _$_findCachedViewById(int var1) { if(this._$_findViewCache == null) { this._$_findViewCache = new SparseArray(); } View var2 = (View)this._$_findViewCache.get(var1); if(var2 == null) { View var10000 = this.getContainerView(); if(var10000 == null) { return null; } var2 = var10000.findViewById(var1); this._$_findViewCache.put(var1, var2); } return var2; } public void _$_clearFindViewByIdCache() { if(this._$_findViewCache != null) { this._$_findViewCache.clear(); } } }
  56. 3. ParcelableରԠ

  57. @Parcelize

  58. @SuppressLint("ParcelCreator") @Parcelize data class Product(val name: String, val id: String)

    : Parcelable
  59. public final int describeContents() { return 0; } public final

    void writeToParcel(@NotNull Parcel parcel, int flags) { Intrinsics.checkParameterIsNotNull(parcel, "parcel"); parcel.writeString(this.name); parcel.writeString(this.id); } public static class Creator implements android.os.Parcelable.Creator { @NotNull public final Product[] newArray(int size) { return new Product[size]; } @NotNull public final Object createFromParcel(@NotNull Parcel in) { Intrinsics.checkParameterIsNotNull(in, "in"); return new Product(in.readString(), in.readString()); } }
  60. ͨͩɺAndroid 4ܥͷҰ෦ͷ୺຤Ͱ Πϯετʔϧʹࣦഊ͢ΔΈ͍ͨ ͜Ε͔Βʹظ଴ʂ 4.1ͷEmulatorͰࣦഊΛ֬ೝࡁΈ

  61. KEEPʹ͸ɺʮSealdΫϥεʹ΋ରԠΛݕ౼ʯͬͯॻ͍ͯ͋Δ ࣮ࡍ͸·ͩͰ͖ͳ͍Έ͍ͨʁͲ͏ͳΔͩΖ͏ʁ

  62. ࠓޙʹظ଴ʂ

  63. ͶɺKotlin Android Extensions ͍͍Ͱ͠ΐʂ

  64. ·ͱΊ • DataBinding΋͍͍͚ͲɺKotlin Android Extensions΋Ͷ • Parcelize͸ɺࠓޙʹظ଴ʂ • KEEPΈΔͷָ͍͠Αʂ

  65. όάʁ Kotlin Android Extensions͕༗ޮʹͳͬͯͳ͍ ϓϩδΣΫͰ΋Ac#vity΍Fragmentʹ _$_findCachedViewByIdͱ͔͕Ͱ͖͍ͯΔʁ

  66. Ko#n Android Extensionsͷத਎ͱ͜Ε͔Β @RyotaMurohoshi 2017/11/09 ୈ7ճ Kotlinษڧձ @SanSan