スマートフォン用の表示で見る
サカエ サカエ SAKAE【代引不可】 その他【直送 SAKAE】【別途送料】 パレットラック H1-5562 [A170809]:DAISHIN工具箱 店中量棚ならダイシン工具箱におまかせ!
Takuji->find; 株式会社はてなでアプリケーションエンジニアやってます、技術的な記事を書いているつもり

サカエ サカエ SAKAE【代引不可】 その他【直送 SAKAE】【別途送料】 パレットラック H1-5562 [A170809]





パレットラック
  • 取寄品
  • 直送
  • 代引不可
  • 車上渡し
  • 別途送料
  • 個人宅不可

納期目安 (メーカーに在庫がある場合)

13:30までにご注文の場合
約3~7日後出荷(土日祝日を除く)
こちらの商品は必ず送料がかかります!北海道?沖縄?離島につきましては別途送料が発生致します。また数量によっても別途送料が発生する場合がございます。金額につきましてはご注文後当店よりご連絡させていただきます。ご注文前にお問い合わせいただければ送料金額を前もってお伝えする事が可能です。★「取寄品」です!ご注文後[商品欠品]及び[商品完売(廃番)]が発生する場合がございます。あらかじめご了承の上ご注文お願いいたします!【代引不可】【直送】【別途送料】【個人宅不可】


※記載の商品画像はイメージ(代表)画像ですので画像だけの情報のみでご購入はお控え頂き、必ず記載内容をご確認下さい。



?組立式
?組立費別途かかりますのでお客様ご自身で組立をお願いいたします。組立ご希望の場合都度ご連絡お願いいたします。
?組立式
?寸法:W2300×D1100×H2100mm
?段数:2段
?耐荷重(棚1段当り):1000kg
?耐荷重(棚1連当り):7000kg
?本体色:グリーン
?組立式
?価格には組立費は含まれておりません。別途申し受けますのでご了承願います。
当社管理番号205894


--検索キーワード--


カタログページ数2017-P0810
サカエ サカエ SAKAE【代引不可】 その他【直送 SAKAE】【別途送料】 パレットラック H1-5562 [A170809]:DAISHIN工具箱 店中量棚ならダイシン工具箱におまかせ! Kotlin Coroutinesをテストする

これは はてなエンジニア Advent Calendar 2019 13日目の記事です。

Kotlin Coroutinesのコルーチンをテストする時に必要なテクニックを紹介します。

コルーチンを同期的に実行したい

コルーチンを使って非同期処理をしているが、テストをする時には同期的に実行してほしいことはよくありますよね。

TestCoroutineScope TestCoroutineDispatcher を使えば簡単にできます。

また、 runBlockingTest を使えばこれらのクラスが自動的に使われます。

kotlin.github.io

kotlin.github.io

CoroutineDispatcherを置き換える

普段使っているCoroutineDispatcherをテスト時に TestCoroutineDispatcher に置き換えるには下記のような方法があります

Dispatchers.Main

kotlinx-coroutines-test に含まれている Dispatchers.setMain / Dispatchers.resetMain を使いましょう


@Before

fun
setUp() {  Dispatchers.setMain(TestCoroutineDispatcher())}
@After

fun
tearDown() {  DIspatchers.resetMain()}

kotlin.github.io

kotlin.github.io

Dispatchers.Default / Dispatchers.IO 他

直接置き換える手段はないので、DIしましょう。

Flowに流れる値をテストする

Flow.collect をコルーチン内で実行すると値を全部受け取るまで処理がそこで止まります。

例えばRoomが返すような終わりのないFlowはキャンセルしない限り collect から先に進めないので、 launch で新しいコルーチンを立ち上げるとよいです。

その時 TestCoroutineScope runBlockingTest を一緒に使ってやると Flow.collect が同期的に実行されます


@Test

fun
test() = runBlockingTest {  
val
flow = 
/ create flow

var
actual = 
null

val
flowCollectJob = launch {    flow.collect {      actual = it    }  }  
/ ここでFlowに値が流れそうなことを何かする

/ yield()でこのコルーチンがDispatcherを一旦手放すことでflow.collectに渡したblockが実行され値が反映される
assertThat(actual).isEqualTo(expected)  
/ 最後にキャンセルしてやらないと完了していないコルーチンがあるので例外が起きる
flowCollectJob.cancel()} 
宣伝

2020年2月に五反田で開催されるDroidKaigi 2020でKotlin Coroutinesについて発表します。Kotlin Coroutinesの使い方に困ってる方は是非見に来てください!

これから始めるKotlin Coroutinesの導入Kotlin Coroutinesが正式リリースされて1年が過ぎ、もはや私たちのAndroidアプリ開発には欠かせないものとなりました。コルーチンはRxJavaのようなストリームやコールバック方式と比べて非同期的な処理を直感的に記述でき、これまでRxJavaを使っていたようなユースケースをある程度置き換えられるようになっています。​​私はこの1年と少しでKotlin Coroutinesを複数のアプリに導入し既存のパラダイムの置き換えを進めてきました。Kotlin Coroutinesの導入を行ったことでAndroidアプリ開発が楽になりましたが、大変になったこともありました。恐らくKotlin Coroutinesが難しく感じて導入をためらっている方もいるでしょう。​このセッションでは、既存のAndroidアプリにKotlin Coroutinesを導入したことによってAndroidアプリ開発がどう変わったか、Kotlin Coroutinesの導入を行ったことで困ったことをどう解決したかなどを紹介します。皆様のKotlin Coroutinesの導入の参考になれば幸いです。​- RxJavaを使って書かれたコードを置き換える- RxJavaを使った世界観にKotlin Coroutinesを混ぜる- Retrofitを用いたHTTP通信をKotlin Coroutinesに対応- RoomをKotlin Coroutinesで利用する- Kotlin CoroutinesとView層との組み合わせ- Kotlin CoroutinesとLiveDataの使い分け- Kotlin CoroutinesをViewModelで活用する- Kotlin Coroutinesとテスト- 例外処理- キャンセル可能に作る

droidkaigi.jp

明日の担当は id:polamjag です。

サカエ サカエ SAKAE【代引不可】 その他【直送 SAKAE】【別途送料】 パレットラック H1-5562 [A170809]:DAISHIN工具箱 店中量棚ならダイシン工具箱におまかせ! KotlinのprovideDelegate operatorについて

こんばんは、Kotlin大好き Android アプリエンジニアの id:takuji31 です。

※これは はてなエンジニア Advent Calendar 2018 21日目の記事です。

provideDelegate operatorについて

provideDelegate operatorはKotlin 1.1からあるオペレーターで、プロパ ティー の移譲オブジェクトを生成することができます。

Delegated Properties - Kotlin Programming Language

このオペレーターを挟むことで、Delegated property生成時にロジックを実行することができ、例えば以下のようなことができます。

  • プロパ ティー の親のオブジェクトに何か操作をする
  • プロパ ティー の生成のパラメーターを検証する
使い方

まずはプロパ ティー になるclassを定義しましょう。

読み書きできるプロパ ティー を作るには kotlin.properties.ReadWriteProperty を実装したclassが必要です。

ここでは Android のSharedPreferencesを操作するStringのpropertyを定義します。


class
SharedPreferencesProperty(
private

val
key: String, 
private

val
defaultValue: String?) :    ReadWriteProperty<PreferencesModel, String?> {    
override

fun
getValue(thisRef: PreferencesModel, property: KProperty<*>): String? {        
return
thisRef.sharedPreferences.getString(key, defaultValue)    }    
override

fun
setValue(thisRef: PreferencesModel, property: KProperty<*>, value: String?) {        thisRef.sharedPreferences.edit().putString(key, value).apply()    }}

次に provideDelegate をもつclassを定義します。

SharedPreferencesに値を出し入れするにはキーを保持する必要がありますが、必ずしもキーがプロパ ティー 名と同じではありません。

そこでプロパ ティー の移譲オブジェクトにキーを渡せるようにします。

もちろんキーは空文字だと困るので検証したいですね。


class
SharedPreferencesPropertyProvider(    
private

val
key: String? = 
null
,    
private

val
defaultValue: String? = 
null
) {    
operator

fun
provideDelegate(        thisRef: PreferencesModel,        prop: KProperty<*>    ): ReadWriteProperty<PreferencesModel, String?> {        
val
propertyName = prop.name        
val
key = key ?: propertyName        require(key.isNotEmpty()) { 
"Key cannot be empty"
}        
return
SharedPreferencesProperty(key, defaultValue)    }}

最後にこのプロパ ティー を使うclassを定義します。


open

class
PreferencesModel(context: Context, name: String) {    
internal

val
sharedPreferences: SharedPreferences = context.getSharedPreferences(name, Context.MODE_PRIVATE)    
protected

fun
stringPreferences(key: String? = 
null
, defaultValue: String? = 
null
) = SharedPreferencesPropertyProvider(key, defaultValue)}
class
UserPreferences(context: Context) : PreferencesModel(context, 
"user"
) {    
var
name: String? 
by
stringPreferences()    
var
profile: String? 
by
stringPreferences(
"profile"
)}

あとはこの UserPreferences インスタンス のプロパ ティー をset/getするとSharedPreferencesを操作できます。

UserPreferences.profile にはキーの値を渡していますが、例えばこの値を空文字にすると インスタンス 生成時に例外が発生するようになります。

正しく インスタンス 生成ができるかはテストでチェックしてやるとよいでしょう。

最後に

provideDelegate メソッドを使うとDelegated propertyを更に柔軟にすることができるでしょう。

明日の担当は id:tkzwtks さんです。

サカエ サカエ SAKAE【代引不可】 その他【直送 SAKAE】【別途送料】 パレットラック H1-5562 [A170809]:DAISHIN工具箱 店中量棚ならダイシン工具箱におまかせ! Architecture Components ViewModelをAutoDisposeに対応させる。

※ これはtakuji31 Advent Calendar 2018、1日目(相当)の記事です。

adventar.org

ViewModel

ViewModelは我々 Android アプリエンジニアの生活になくてはならない コンポーネント の一つである。

Android のActivityの インスタンス 単体のライフサイクルは特定の画面のライフサイクルより短く、画面回転やメ モリー 不足で簡単に消される。

だが通信などの非同期処理は画面を完全に抜け出すまでやっていてほしいし、データも保持されてほしく、そういう時にViewModelを使う。

使い方は公式ドキュメントを見てほしい。

developer.android.com

AutoDispose

AutoDisposeは Uber が公開しているRxJava2のDisposableを自動的にdisposeするライブラリーである。

大半の処理は実行を指示したライフサイクルに対応するライフサイクルで処理をキャンセル(createならdestroy、resumeならpause)したいものである。

これをいい感じに自動的にやってくれるライブラリーがAutoDisposeだ。

1.0.0でandroidxにも対応していて安心。

github.com

使い方は簡単でRxJavaのObservableやSingleをsubscribeする前に

observable  .autoDisposable(scope())  .subscribe()

などとしてやるだけである。

これだけで現在の状態に対応したライフサイクルイベントが起きた時にdisposeされる。

ViewModelをAutoDisposeに対応させる

AutoDisposeには ScopeProvider というinterfaceがあり、これを使うと今のスコープをAutoDisposeに知らせることができる。

ScopeProvider#requestScope CompletableSource を返せばこれが完了した時に Disposable がdisposeされる。

Fragment Activity といった LifecycleOwner ScopeProvider を継承した LifecycleScopeProvider (を実装した AndroidLifecycleScopeProvider ) によって Android のActivityやFragmentのライフサイクルに応じたスコープを返すようになっている。

一方でViewModelは onCleared という単一のライフサイクルメソッドを持っている。

AutoDisposeで管理されるViewModel内のDisposableは全て onCleared が呼ばれた時に破棄されてほしい。

なので ScopeProvider を実装して onCleared が呼ばれた時に完了する CompletableSource を返すようにしてやればよい。


abstract

class
BaseViewModel : ViewModel(), ScopeProvider {  
private

val
onClearedSubject = CompletableSubject.create();  
override

fun
requestScope() : CompletableSource = onClearedSubject  
@CallSuper

override

fun
onCleared() {    onClearedSubject.onComplete()  }}
class
HogeViewModel: BaseViewModel() {  
init
{    observable      .autoDisposable(
this
)      .subscribe()  }}
最後に

明日も何か書きます。

中量棚ならダイシン工具箱におまかせ!。サカエ SAKAE 【代引不可】【直送】【別途送料】 パレットラック H1-5562 [A170809]
サカエ サカエ SAKAE【代引不可】 その他【直送 SAKAE】【別途送料】 パレットラック H1-5562 [A170809]:DAISHIN工具箱 店中量棚ならダイシン工具箱におまかせ! 【ポイント5倍】 【直送品】 PiCa (ピカ) 簡易アルミゲート キャスターゲート GTO-30 【大型】3-6732-06 石英乳鉢 90×110×40mm河川·内海用オイルフェンス (型式承認品)第P-222号【個数:1個】アクアシステム アクア DF4D20AS 直送 代引不可·他メーカー同梱不可 エアードラムポンプ エアダイヤフラムタイプ【ポイント5倍】HIOKI アナログオームハイテスタ IR408211 6031ステンレス ファインメッシュ 溶接金網 線径(mm):0.7|網目(mm):5.65|ピッチ(芯々)(mm):6.35|大きさ:1220mm×29m SUS304アズワン(AS ONE) 2次元バーコードリーダー USBインターフェース(3-4980-01)中量スライドラック サカエ MSR1812K05T【中古】マキタ(Makita) 90mm高圧エア釘打 赤 AN934H【送料無料】【代引不可】 TAIYO 油圧シリンダ 100H-22CB80BB450-AB (585-0339) 《油圧シリンダ》【メーカー在庫あり】 エスコ ESCO 0.05-200m レーザー距離計 000012247267 HD店TOA 携帯型送信機(ツーピース型) WM-1100 4309SAKAE/サカエ 【代引不可】中量棚BW型(アイボリー) BW-1745アートグリーン 人工観葉植物 光触媒 光の楽園 アートトラベラーズパーム2.1 117C750 2020年版サカエ SAKAE 【代引不可】【直送】【別途送料】 パレットラック H1-5562 [A170809]エスコ(ESCO)  φ 22- 115mm ··· EA510AG-3WILLIAMS 1‐1/2ドライブ エクステンション 15インチ インパクト JHW8115MITOLOY 2-1/2 インパクトレンチ用ソケット スタンダードタイプ(6角)140mm ※取寄品 P20-140【送料無料】 ·KBL·農業用·コンバイン用 ゴムクローラ 幅400×ピッチ90×リンク34【芯金:W】【パターン:B】 4034NJS ※代引不可※【観葉植物】フラワーコンシェルジュが厳選した花屋の観葉植物 90000円 ラッピング無料、メッセージカード無料 【楽ギフ_メッセ入力】モクバ印 アングルカッター R40 D60人工観葉植物 光の楽園 トロピカルアレカパ-ム 2.0 124F600【造花/フェイク/リビング/玄関/アートフラワー/インテリアグリーン】【中古】TOKU 強力型インパクトレンチ1/2 MI-17 MI17日東 ニトフロン粘着テープNo.973UL 0.15mm×300mm×10m 973X15X300【直送品】 三菱 (MITSUBISHI) 高性能省エネモータ SF-PRB 11KW 6P 200V (SF-PRB-11KW-6P)ステンレス ファインメッシュ 溶接金網 線径(mm):1.2|網目(mm):8.8|ピッチ(芯々)(mm):10|大きさ:1000mm×11m SUS304送料無料 東日興産 クボタ SR/AR/ARN/ER専用 コンバインゴムクローラ 360幅×79ピッチ オフセット コマ数40CE3679シリーズ OEパターン CE367940トラスコ中山 TRUSCO EGW963V2JYG イーグルワゴン 600X400 引出付 4輪自在 YG色【ポイント5倍】エレクター ミニカート NMCD 1063 ThreeTen BackportのInstant.plus(long, TemporalUnit)は年を足せない

Androiderならきっとみんな大好きなはずのThreeTen Backportに関しての雑メモ。

今から100年後のInstantが欲しくなって Instant.now().plus(100, ChronoUnit.YEARS) ってやってみたけど UnsupportedTemporalTypeException で死んだ。

コードを読んでみると ChronoUnit.YEARS はサポートされていなくて以下の ChronoUnit しか使えなかった。

  • NANOS
  • MICROS
  • MILLIS
  • SECONDS
  • HOURS
  • HALF_DAYS
  • DAYS

月と年の計算は曖昧な部分(うるう年とか)があるからサポートできないのだろうか。

とりあえず厳格に100年後が欲しかったわけじゃないので plus(36500, ChronoUnit.DAYS) でなんとかすることにした。

問題のコードはこの辺り↓

https://github.com/ThreeTen/threetenbp/blob/9233702f6905c3b172f57fcda3fc278ad1542cac/src/main/java/org/threeten/bp/Instant.java#L710

サカエ サカエ SAKAE【代引不可】 その他【直送 SAKAE】【別途送料】 パレットラック H1-5562 [A170809]:DAISHIN工具箱 店中量棚ならダイシン工具箱におまかせ! RecyclerView.ItemDecorationでgetItemOffsetsの値を変えた時、レイアウトはどう動くか

雑なメモ

RecyclerView.ItemDecoration を使ってitemのoffset(bottom)を調整する機会があった。

ある位置を基準にしつつ、offsetを調整+スクロールして基準位置にあったitemが同じ位置に見えている必要があったのだが、なぜかズレる。

よく見てみたら 見えている一番上のitem の位置が動かず、下にズレているのだ。

どうやら今見えている一番上のitemを基準にレイアウトが決定されるようだった。

仕方がないので基準位置より上にあるViewのoffsetを計算してその分だけスクロールすることにした。

サカエ サカエ SAKAE【代引不可】 その他【直送 SAKAE】【別途送料】 パレットラック H1-5562 [A170809]:DAISHIN工具箱 店中量棚ならダイシン工具箱におまかせ! lateinitの行儀の良い使い方

以前勉強会で「Kotlinの

サカエ サカエ SAKAE【代引不可】 その他【直送 SAKAE】【別途送料】 パレットラック H1-5562 [A170809]:DAISHIN工具箱 店中量棚ならダイシン工具箱におまかせ!

lateinit Delegates.notNull() の使い分けがよく分からない」というお話をいただいた時に"基本的には Delegates.notNull() を使うべきではないか?" と答えたしそれより前から最近もずっと思っていたのだが、(DroidKaigiの発表を聞くなどする感じ)どうも違うのではないかと思えてきた。

そのため、ここでlateinitの仕様について整理しつつ、そこから導き出される行儀の良い使い方を考察する。

結論
  • kaptを利用して Java のコードからフィールドを操作したい場合は lateinit を使うべき
    • フィールドが露出すると不都合がある場合は Delegates.notNull() を使うべき
  • lateinit を普通に遅延初期化目的で使うならprivateで使うべき
  • 遅延初期化するが、タイミングは最初にアクセスされた時でよい&変更されないなら lazy で十分
  • 小さなオブジェクトが大量に生成されると困るくらいパフォーマンスを気にする部分では lateinit を使うとよい
lateinitとは

KotlinでNonNullなプロパティーの初期化をconstructorより後に遅らせられる機能。

元々はkaptで(例えば)Dagger2から インスタンス をプロパティーに直接代入できない、みたいなことを解決するアプローチとして追加された。

blog.jetbrains.com

lateinitの使い方

lateinit をプロパティー定義の前に書く。


lateinit

var
viewModel: HogeViewModel
fun
onCreate(savedInstanceState: Bundle?) {   
/ DI
component.inject(
this
)   viewModel.fuga 
/ インスタンスにアクセスできる
}
制約
  • valには使えない(以前は使えたが今は使えない)
  • Nullableには使えない
  • プリミティブ型には使えない
  • 使うことで Java からはそのプロパティーのfieldがプロパティーと同じvisibilityで見える
    • private 以外にすると外から見える可能性がある → 意図しない使い方になる可能性
Delegates.notNull() との違い
  • lateinit Delegate オブジェクトが作られないので、大量に使う場合にパフォーマンス的に有利
  • Delegates.notNull() はプリミティブ型にも使える
lazyとの違い
  • lazy は値をsetできない(1回限りの遅延初期化)
  • lazy はNullableでも使える
最後に

意外とlateinitもっとカジュアルに使ってもいいのかもしれない。

サカエ サカエ SAKAE【代引不可】 その他【直送 SAKAE】【別途送料】 パレットラック H1-5562 [A170809]
サカエ サカエ SAKAE【代引不可】 その他【直送 SAKAE】【別途送料】 パレットラック H1-5562 [A170809]:DAISHIN工具箱 店中量棚ならダイシン工具箱におまかせ! KotlinのSealed Classを使いこなす

こんにちは、三度の飯よりKotlinが好きな id:takuji31 です。

※ これは、 はてなエンジニア Advent Calendar 2017 7日目の記事です。6日目は id:hayajo_77 さんの「Webオペレーションエンジニアとし研修して1ヶ月経ちました」でした。

hayajo.hatenablog.jp

今日は私が愛してやまないKotlinのSealed Classの使い方について紹介します。

Sealed Classについて

Sealed Classとは継承を制限して、階層を明確にできるクラスです。

詳しくは公式ドキュメントを参照してください。

Sealed Classes - Kotlin Programming Language

もう少し分かりやすく言うと、1つのファイル内でだけ継承できるクラスです。

Sealed Classを使う利点普通の( final or open )クラスと比べて

外部からの継承を制限できるので、 コンパイル 時に子クラスの階層が全て明らかになります。

これで何ができるかというと、when式とis 演算子 の組み合わせで網羅性のチェックができます。

例えば下のコードのように、通常の A を継承する B/C/D というクラスがある時に


open

class
A
class
B : A()
class
C : A()
class
D : A()

このAの子クラスの インスタンス がどのクラスか判定して何か値を返す関数は


fun
isSomething(obj : A) : 
Boolean
{  
return

when
(obj) {    
is
B 
->

true

is
C 
->

true

is
D 
->

false
}}

と書くと コンパイル エラーになる( B/C/D 以外の可能性がないことを判別できない)ので、以下のように書くと思います。


fun
isSomething(obj : A) : 
Boolean
{  
return

when
(obj) {    
is
B 
->

true

is
C 
->

true

is
D 
->

false

else

->

throw
RuntimeException(
"Not reached!!!!"
)  }}

elseは(自分達が書いているコード的には)絶対通らないはずだけど、例外を投げるか何らかの値を返す必要があります。

もちろんこのコードがライブラリーにあったとして、利用者が A を継承した E というクラスを作って渡すと、このコードはelseに到達しますね。

Sealed Classにすることで、 コンパイラ ーがこの A の子クラスは B/C/D しかないことを知られるので、最初のコードでも問題なくなります。

こうすることで、後で自分で A を継承する別のクラスを作ると、ここに選択肢を追加しないと コンパイル が通らなくなり、処理の追加漏れがなくなります。

Enum と比べて

前の項で書いている内容は、 Enum でも実現できますね。

Enum と比べてSealed Classを利用する利点は、「Sealed Classを継承するのはobjectでもclassでもよい」ということではないでしょうか。

Sealed Classの子クラスそれぞれを Enum の値のように扱うことで、「 Enum の各値に可変の値を持たせるような仕組み」ができます。

SwiftだとAssociated Value と呼ばれるものですね。

使い方

使い方は簡単で、class宣言の前に sealed と書き、子クラスを全て同じファイル内で宣言するだけです。


その他
sealed

class
A
class
B : A()
class
C : A()
class
D : A()
object
Z : A()

こうすることで、クラス A はこのファイル内でしか継承できなくなります。

また、 A はabstractなクラスかつ、 コンストラクター がprivateになるので、直接 インスタンス 生成はできなくなります。

あとは通常のクラスと同じように使います。

どういう使い方をしている?

私が実際にSealed Classを使うシチュエーションを紹介します。

決まった文字列(全てが定数ではない)を受け取りたい時

これはSealed Classの「ファイル外で継承できない」仕組みを活用する例です。

例えば Android アプリで Google Analytics にスクリーン名を送りたい時、スクリーンは定められた値なので、大半が定数で定義可能です。

しかし、完全な定数で済めばいいのですが、ページングをしている時にパラメーターとしてページ数を送りたいかもしれません。

また、普通に String を送る運用だとミスって意味の分からない文字列を送ってしまうかもしれません。

こういった場合にそれぞれのスクリーン用にSealed Classを継承したobjectやclassを作り、 Google Analytics の送信用のラッパーを用意して、そこで値を分解して送るとこの問題を防ぐことができます。


sealed

class
GAScreen() {  
abstract

val
screenName: String  
open

class
Simple(
override

val
screenName: String) : GAScreen()  
object
Top : Simple(
"top"
)  
object
Settings : Simple(
"settings"
)  
object
List(
private

val
page: 
Int
) : GAScreen() {    
override

val
screenName: String = 
"list[page=

$page

]"
}}

ラッパー側は以下のようになります。


class
GoogleAnalyticsWrapper() {  
fun
sendScreen(screen: GAScreen) {    
val
screenName = screen.screenName    
/ ここでスクリーン名を送る
}}

こうすることで、うっかり変な文字列を送ることがなくなります。

色々な値を受け取って表示するActivityを起動するIntentに渡すパラメーターオブジェクト

こちらは"すごい Enum "っぽく使う例ですね。

Intentに複数のパラメーターをセットしたい時、全部を別々に手で受け取るのは面倒ですよね。

そのパラメーターの中にNullableなものがあって、別のパラメーターの値によって値が入ってなかったりすると思います。

こういう時にパラメーターオブジェクトを作って、Parcelableにして渡すのが有効と考えられます。


sealed

class
MainScreen() {  
object
Top : MainScreen()  
object
Settings : MainScreen()  
class
Feed(
val
skipTutorial: 
Boolean
) : MainScreen()  
class
Category(
val
category: Category) : MainScreen()  
class
EntryList(
val
initialTab: Tab) : MainScreen()}

これをActivity側で受け取ってwhen式を使うなどして処理してやります。


when
(screen) {  
is
Top 
->
{    openTop()  }  
is
Settings 
->
{    openSettings()  }  
is
Feed 
->
{    openFeed(screen.skipTutorial)  }  
is
Category 
->
{    openCategory(screen.category)  }  
is
EntryList 
->
{    openEntryList(screen.initialTab)  }}
最後に

KotlinのSealed Classを使って堅牢な設計のアプリを作りましょう。

明日の担当は id:aereal さんです!

スターをつけました

引用をストックしました

e0a89c43bd07f8881fc82a-
4aa0f91a2.ir
b4fec526f46a0b8b4f6c648e14
66a6f/99965867
236/9
/8e9025.zm
e601a973f542b3619316/bc0bad067c5d.ventures
c920ab540070558f7094cb3a74.va
6ab8ae397ce66/99e5e85eb924477
d20bf62c9f0b8

引用するにはまずログインしてください

引用をストックできませんでした。再度お試しください

限定公開記事のため引用できません。

読者です 読者をやめる 読者になる 読者になる