Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Kotin Android Extensionsの中身とこれから
Search
RyotaMurohoshi
November 09, 2017
Technology
2
750
Kotin Android Extensionsの中身とこれから
2017/11/09 第7回 Kotlin勉強会 @SanSan
の
むろほしりょうた(@RyotaMurohoshi)
の資料です。
RyotaMurohoshi
November 09, 2017
Tweet
Share
More Decks by RyotaMurohoshi
See All by RyotaMurohoshi
Unityの合同同人誌や合同商業誌を書いてる僕は感想やレビューや評価が欲しい
ryotamurohoshi
0
490
Unity 2021.1での Unityパッケージの名称変更について
ryotamurohoshi
0
680
Odin Validationはいいぞ!
ryotamurohoshi
2
910
Tilemapはいいぞ!2020 〜すごいぞ、プロジェクト専用拡張Brush〜
ryotamurohoshi
0
2.3k
Unityでも、新しいC#
ryotamurohoshi
0
1.3k
Riderはいいぞ!
ryotamurohoshi
1
3.4k
Riderのススメ〜俺はRiderここが好き〜
ryotamurohoshi
1
2.3k
Unity開発者に伝えたい.NETのこと
ryotamurohoshi
4
37k
ImportedLinqのススメ
ryotamurohoshi
0
1.3k
Other Decks in Technology
See All in Technology
役員・マネージャー・著者・エンジニアそれぞれの立場から見たAWS認定資格
nrinetcom
PRO
5
6.9k
AIエージェント開発のノウハウと課題
pharma_x_tech
9
5k
ExaDB-XSで利用されているExadata Exascaleについて
oracle4engineer
PRO
3
310
DeepSeekとは?何がいいの? - Databricksと学ぶDeepSeek! 〜これからのLLMに備えよ!〜
taka_aki
2
190
開発者体験を定量的に把握する手法と活用事例
ham0215
0
140
Ruby on Railsで持続可能な開発を行うために取り組んでいること
am1157154
3
180
スクラムというコンフォートゾーンから抜け出そう!プロジェクト全体に目を向けるインセプションデッキ / Inception Deck for seeing the whole project
takaking22
3
190
QAエンジニアが スクラムマスターをすると いいなぁと思った話
____rina____
0
180
マルチアカウント環境における組織ポリシーについて まとめてみる
nrinetcom
PRO
2
110
20250304_赤煉瓦倉庫_DeepSeek_Deep_Dive
hiouchiy
2
140
マーケットプレイス版Oracle WebCenter Content For OCI
oracle4engineer
PRO
3
550
AIエージェント入門
minorun365
PRO
34
20k
Featured
See All Featured
Building Flexible Design Systems
yeseniaperezcruz
328
38k
Rebuilding a faster, lazier Slack
samanthasiow
80
8.9k
What's in a price? How to price your products and services
michaelherold
244
12k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
233
17k
How STYLIGHT went responsive
nonsquared
99
5.4k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.5k
How GitHub (no longer) Works
holman
314
140k
Adopting Sorbet at Scale
ufuk
75
9.2k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
251
21k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
330
21k
Code Reviewing Like a Champion
maltzj
521
39k
Producing Creativity
orderedlist
PRO
344
40k
Transcript
Ko#n Android Extensionsͷதͱ͜Ε͔Β @RyotaMurohoshi 2017/11/09 ୈ7ճ Kotlinษڧձ @SanSan
Kotlin Android Extensions ͍ͬͯΔਓʁ
ͬͺΓDataBindingͰ͔͢ʁ ͦΕͱankoͰ͔͢ʁ
Kotlin Android Extensions ɺ͖Ͱ͢
ɹࣗݾհ @RyotaMurohoshi
࠷ۙձࣾͰɺKotlinຊಡॻձΛ࢝Ί·ͨ͠
Tools > Kotlin > Show Kotlin Bytecode > Decompile ͜ΕΛԿΑΓઌʹڭ͑ͯ͋͛Δͱ͍͍ͱࢥ͏ʂ
ʮKo#n Android Extensionsͷ தͱ͜Ε͔Βʯ ʹ͍ͭͯ͠·͢ Kotlin 1.1.51ʹͯ
Kotlin Android Extensions ʹ͍͓ͭͯ͞Β͍
ViewͷΠϯελϯεʹ؆୯ʹ ΞΫηεͰ͖Δͭ
gadleͷதͰ͜͏ॻ͘ (͍ͯ͏͔σϑΥϧτͰೖ͍ͬͯΔ) apply plugin: 'kotlin-android-extensions'
<?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>
ίʔυͰtextViewͱ͍͏໊લͰ TextViewܕͱͯ͠ΞΫηεͰ͖Δ class MainActivity : Activity() { override fun onCreate(savedInstanceState:
Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // TextViewܕͷtextView͕ʂ textView.text = "Hello Activity" } }
// TextViewܕͷtextView͕ʂ textView.text = "Hello Activity"
؆୯Ͱ͠ΐʂ ศརͰ͠ΐʂ
தΈͯΈ·͠ΐ͏
Tools > Kotlin > Show Kotlin Bytecode > Decompile
class MainActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // TextViewܕͷtextView͕ʂ textView.text = "Hello Activity" } }
/* ུ */ 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(); } } }
/* ུ */ 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; } /* ུ */
σίϯύΠϧͯ͠ΈΔͱ • _$_findViewCacheͱ͍͏HashMapΛϑΟʔϧυͱͯ࣋ͭ͠ • _$_findCachedViewByIdϝιουɺ • Ҿʹͱͬͨid͕HashMapʹ͋ΕͦΕΛฦ͠ • ͳ͚Ε୳ࡧɺHashMapʹೖΕͨޙɺͦΕΛฦ͢ _$_findViewCache_findCachedViewByIdɺKotlinͰίʔυͰ͔͚ͳ͍ɻཁʮ``ʯ
/* ུ */ 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; } /* ུ */
͜Μͳײ͡ͷ֦ுϓϩύςΟ͕ੜ͑ΔΘ͚Ͱͳ͍ʂ // ͜Μͳײ͡͡Όͳ͍ʂ // Ωϟογϡػߏ͋ΔΑ val MainActivity.textView : TextView get()
= findViewById(R.id.textView)
FragmentͰKotlin Android Extensions͑·͢ FragmentͰಉ͡Α͏ʹHashMapͰͷΩϟογϡػߏʂ
֦ுؔͷதͰʂ package com.teammurosta import kotlinx.android.synthetic.main.activity_main.* fun MainActivity.updateText(text: String) { this.textView.text
= text }
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") } }
// ֦ுؔͷσίϯύΠϧ݁Ռ 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); } }
// 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(); } } }
Կ͕ԿͰΩϟογϡ͢ΔΘ͚͡Όͳ͍
֦ுؔͷதͰʂMainAc'vity -> Ac'vityʹมߋʂ package com.teammurosta import kotlinx.android.synthetic.main.activity_main.* fun Activity.updateText(text: String)
{ this.textView.text = text }
// ֦ுؔͷσίϯύΠϧ݁Ռ 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); } }
android.app.Ac+vityΫϥε android.support.v7.app.AppCompatAc2vityΫϥεɺ android.support.v4.app.FragmentΫϥεΛ֦ுͨ͠߹ɺ ී௨ʹfindViewByIdΛݺͿ
ViewHolderͰͷ׆༻ྫ
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 } }
σίϯύΠϧ݁ՌΛΈΔͱΩϟογϡ͍ͯ͠ͳ͍ 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); } }
͔͜͜Βઌɺ͜Ε͔Βͷ
Kotlin 1.1.4ͰύϫʔΞοϓ experimental͚ͩͲ androidExtensions { experimental = true }
1. Ωϟογϡઓུ
@ContainerOp,ons
ࠓ·ͰΩϟογϡHashMapͷΈ ʮSparseArrayʯͱʮΩϟογϡ͠ͳ͍ʯ ΛબΔΑ͏ʹͳͬͨʂ
// ↓Ξϊςʔγϣϯ @ContainerOptions(CacheImplementation.SPARSE_ARRAY) class MainActivity : Activity() { override fun
onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) textView.text = "Hello" } }
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(); } } }
// ↓Ξϊςʔγϣϯ @ContainerOptions(CacheImplementation.NO_CACHE) class MainActivity : Activity() { override fun
onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) textView.text = "Hello" } }
public final class MainActivity extends Activity { protected void onCreate(@Nullable
Bundle savedInstanceState) { super.onCreate(savedInstanceState); ((TextView)this.findViewById(id.textView)).setText((CharSequence)"Hello"); } }
ҰׅมߋͰ͖Δ ະυΩϡϝϯτԽͰ༷มߋ͢Δ͔͠Εͳ͍͚Ͳ
app/build.gradleͰઃఆ androidExtensions { experimental = true defaultCacheImplementation = "sparse_array" //
hash_map or none }
ΩϟογϡʹSparseArrayɺͬͨ΄͏͕͍͍ͷʁ
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ΑΓ
2. ViewHolderରԠ
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 } }
σίϯύΠϧ݁ՌΛΈΔͱΩϟογϡ͍ͯ͠ͳ͍ 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); } }
Ac#vityFragmentͷαϒΫϥεΈ͍ͨʹ Ωϟογϡ͢Δʹʁ
LayoutContainer
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 } }
Ωϟογϡ͢ΔΑ͏ʹʂ 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(); } } }
3. ParcelableରԠ
@Parcelize
@SuppressLint("ParcelCreator") @Parcelize data class Product(val name: String, val id: String)
: Parcelable
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()); } }
ͨͩɺAndroid 4ܥͷҰ෦ͷͰ Πϯετʔϧʹࣦഊ͢ΔΈ͍ͨ ͜Ε͔Βʹظʂ 4.1ͷEmulatorͰࣦഊΛ֬ೝࡁΈ
KEEPʹɺʮSealdΫϥεʹରԠΛݕ౼ʯͬͯॻ͍ͯ͋Δ ࣮ࡍ·ͩͰ͖ͳ͍Έ͍ͨʁͲ͏ͳΔͩΖ͏ʁ
ࠓޙʹظʂ
ͶɺKotlin Android Extensions ͍͍Ͱ͠ΐʂ
·ͱΊ • DataBinding͍͍͚ͲɺKotlin Android ExtensionsͶ • Parcelizeɺࠓޙʹظʂ • KEEPΈΔͷָ͍͠Αʂ
όάʁ Kotlin Android Extensions͕༗ޮʹͳͬͯͳ͍ ϓϩδΣΫͰAc#vityFragmentʹ _$_findCachedViewByIdͱ͔͕Ͱ͖͍ͯΔʁ
Ko#n Android Extensionsͷதͱ͜Ε͔Β @RyotaMurohoshi 2017/11/09 ୈ7ճ Kotlinษڧձ @SanSan