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
800
Kotin Android Extensionsの中身とこれから
2017/11/09 第7回 Kotlin勉強会 @SanSan
の
むろほしりょうた(@RyotaMurohoshi)
の資料です。
RyotaMurohoshi
November 09, 2017
Tweet
Share
More Decks by RyotaMurohoshi
See All by RyotaMurohoshi
Tilemapのアップデートについて
ryotamurohoshi
0
46
Unityの合同同人誌や合同商業誌を書いてる僕は感想やレビューや評価が欲しい
ryotamurohoshi
0
550
Unity 2021.1での Unityパッケージの名称変更について
ryotamurohoshi
0
740
Odin Validationはいいぞ!
ryotamurohoshi
2
1k
Tilemapはいいぞ!2020 〜すごいぞ、プロジェクト専用拡張Brush〜
ryotamurohoshi
0
2.4k
Unityでも、新しいC#
ryotamurohoshi
0
1.4k
Riderはいいぞ!
ryotamurohoshi
1
3.6k
Riderのススメ〜俺はRiderここが好き〜
ryotamurohoshi
1
2.5k
Unity開発者に伝えたい.NETのこと
ryotamurohoshi
4
38k
Other Decks in Technology
See All in Technology
能登半島地震で見えた災害対応の課題と組織変革の重要性
ditccsugii
0
950
能登半島災害現場エンジニアクロストーク 【JAWS FESTA 2025 in 金沢】
ditccsugii
0
830
CoRL 2025 Survey
harukiabe
1
200
プレーリーカードを活用しよう❗❗デジタル名刺交換からはじまるイベント会場交流のススメ
tsukaman
0
160
BI ツールはもういらない?Amazon RedShift & MCP Server で試みる新しいデータ分析アプローチ
cdataj
0
160
これがLambdaレス時代のChatOpsだ!実例で学ぶAmazon Q Developerカスタムアクション活用法
iwamot
PRO
6
1.1k
ソースを読むプロセスの例
sat
PRO
10
3.6k
Wasmのエコシステムを使った ツール作成方法
askua
0
170
いまからでも遅くない!SSL/TLS証明書超入門(It's not too late to start! SSL/TLS Certificates: The Absolute Beginner's Guide)
norimuraz
0
240
速習AGENTS.md:5分で精度を上げる "3ブロック" テンプレ
ismk
6
1.6k
ビズリーチ求職者検索におけるPLMとLLMの活用 / Search Engineering MEET UP_2-1
visional_engineering_and_design
1
130
Introduction to Sansan, inc / Sansan Global Development Center, Inc.
sansan33
PRO
0
2.8k
Featured
See All Featured
Site-Speed That Sticks
csswizardry
12
900
Art, The Web, and Tiny UX
lynnandtonic
303
21k
Automating Front-end Workflow
addyosmani
1371
200k
Product Roadmaps are Hard
iamctodd
PRO
54
11k
Writing Fast Ruby
sferik
629
62k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
48
9.7k
[RailsConf 2023] Rails as a piece of cake
palkan
57
5.9k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
140
34k
Building Better People: How to give real-time feedback that sticks.
wjessup
369
20k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.1k
Rebuilding a faster, lazier Slack
samanthasiow
84
9.2k
Scaling GitHub
holman
463
140k
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