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
720
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
370
Unity 2021.1での Unityパッケージの名称変更について
ryotamurohoshi
0
630
Odin Validationはいいぞ!
ryotamurohoshi
2
860
Tilemapはいいぞ!2020 〜すごいぞ、プロジェクト専用拡張Brush〜
ryotamurohoshi
0
2.3k
Unityでも、新しいC#
ryotamurohoshi
0
1.2k
Riderはいいぞ!
ryotamurohoshi
1
3.2k
Riderのススメ〜俺はRiderここが好き〜
ryotamurohoshi
1
2.2k
Unity開発者に伝えたい.NETのこと
ryotamurohoshi
4
36k
ImportedLinqのススメ
ryotamurohoshi
0
1.3k
Other Decks in Technology
See All in Technology
RubyのWebアプリケーションを50倍速くする方法 / How to Make a Ruby Web Application 50 Times Faster
hogelog
3
940
Why does continuous profiling matter to developers? #appdevelopercon
salaboy
0
190
AWS Media Services 最新サービスアップデート 2024
eijikominami
0
200
誰も全体を知らない ~ ロールの垣根を超えて引き上げる開発生産性 / Boosting Development Productivity Across Roles
kakehashi
1
230
開発生産性を上げながらビジネスも30倍成長させてきたチームの姿
kamina_zzz
2
1.7k
OTelCol_TailSampling_and_SpanMetrics
gumamon
1
160
Evangelismo técnico: ¿qué, cómo y por qué?
trishagee
0
360
iOS/Androidで同じUI体験をネ イティブで作成する際に気をつ けたい落とし穴
fumiyasac0921
1
110
スクラム成熟度セルフチェックツールを作って得た学びとその活用法
coincheck_recruit
1
140
Shopifyアプリ開発における Shopifyの機能活用
sonatard
4
250
これまでの計測・開発・デプロイ方法全部見せます! / Findy ISUCON 2024-11-14
tohutohu
3
370
Lambdaと地方とコミュニティ
miu_crescent
2
370
Featured
See All Featured
Mobile First: as difficult as doing things right
swwweet
222
8.9k
The Cult of Friendly URLs
andyhume
78
6k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
27
4.3k
Git: the NoSQL Database
bkeepers
PRO
427
64k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
246
1.3M
No one is an island. Learnings from fostering a developers community.
thoeni
19
3k
Documentation Writing (for coders)
carmenintech
65
4.4k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
4
370
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
28
2k
What’s in a name? Adding method to the madness
productmarketing
PRO
22
3.1k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
29
2.3k
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