[Android] Activity/Fragmentへのデータ渡しをdelegated property使って楽にする

スポンサーリンク

はじめに

Activityを起動するときのIntentにデータを詰めて渡すとき。

Fragmentを起動するときのBundleにデータ詰めて渡すとき。

いつもKey名を定数化して渡すの面倒くさいなぁとか思ってた。

delegated propertyを使うと楽になる、、、という感じがしたので紹介する。

今までの渡し方

//
companion object {
const val pushKey = "pushKey"
const val fromTopKey = "fromTopKey"
fun start(context: Context, pushMsg: String? = null, fromTop: Boolean = false) {
context.startActivity(Intent(context, HowToActivity::class.java).apply{
putExtra(pushKey, pushMsg)
putExtra(pushKey, fromTopKey)
})
}
}

private var pushMsg: String? = null
private var fromTop: Boolean = false

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

intent?.apply{
pushMsg = getStringExtra(pushKey)
fromTop = getBooleanExtra(fromTopKey)
}
}

Activityの例だけど、一般的にcompanion objectにActivityを起動する or Intentを取得させるコード書くと思う。そこで詰めたデータをonCreateで取り出すってのが結構最近の形なのかなぁって思ってる。いろんなプロジェクト見てもこの形で書いてあることが結構あるし。

delegated propertyを使ったやり方

Propertyクラスを用意

//
private object UNINITIALIZED_VALUE_FOR_EXTRA
@Suppress("UNCHECKED_CAST")
class Extra<T> : ReadWriteProperty<Activity, T> {

var field: Any? = UNINITIALIZED_VALUE_FOR_EXTRA

override fun getValue(thisRef: Activity, property: KProperty<*>): T {
if (field == UNINITIALIZED_VALUE_FOR_EXTRA) {
field = thisRef.intent.extras?.get(property.name)
}
return field as T
}

override fun setValue(thisRef: Activity, property: KProperty<*>, value: T) {
field = value
}
}

使ってみる

//
companion object {
fun start(context: Context, pushMsg: String? = null, fromTop: Boolean = false) {
context.startActivity(Intent(context, HowToActivity::class.java).apply{
putExtra(HowToActivity::pushMsg.name, pushMsg)
putExtra(HowToActivity::fromTop.name, fromTop)
})
}
}

private var pushMsg: String? by Extra()
private var fromTop: Boolean by Extra()

onCreateで取り出さなくても、フィールド変数にアクセスするときにPropertyクラスがデータを取り出してくれる。定数も用意しなくて良い。行数も減ってスッキリ!すると思ってる。

欠点・・・。

フィールド変数を用意しないといけない。単発で使うデータとかフィールドに置かないことがあると思うんだけど、それができない。良い方法も思いつかない・・・。まぁ、フィールド変数に置くだけだから多用しても良いかもしれないけど。

おわりに

Fragment用のPropertyクラス書いておく。Fragment側の使い方は↑で書いたActivityのやつと基本的に一緒。

//
private object UNINITIALIZED_VALUE_FOR_ARGMENTS

@Suppress("UNCHECKED_CAST")
class Arguments<T> : ReadWriteProperty<Fragment, T> {

var field: Any? = UNINITIALIZED_VALUE_FOR_ARGMENTS

override fun getValue(thisRef: Fragment, property: KProperty<*>): T {
if (field == UNINITIALIZED_VALUE_FOR_ARGMENTS) {
field = thisRef.arguments?.get(property.name)
}
return field as T
}

override fun setValue(thisRef: Fragment, property: KProperty<*>, value: T) {
field = value
}
}
Amazon.co.jp: Google Android グーグル アンドロイド アンドリュー・ベル ミニコレクタブル フィギュア/Andrew Bell Designer Toy Figure [並行輸入品] : おもちゃ
Amazon.co.jp: Google Android グーグル アンドロイド アンドリュー・ベル ミニコレクタブル フィギュア/Andrew Bell Designer Toy Figure : おもちゃ
タイトルとURLをコピーしました