おさらい
val printHelloWorld = {
println("Hello, world!")
}
printHelloWorld()
//printHelloWorld.invoke()
これで以下が出力される。
Hello, world!
同様に引数を渡す。
val printGreeting = { word: String, name: String ->
println("$word, $name")
}
printGreeting("おはよう", "太郎")
printGreeting.invoke("こんにちは", "次郎")
おはよう, 太郎
こんにちは, 次郎
これまでのコールバック
inferface を使ったコールバックは kotlin では以下のように書けます。
interface CallBackListener {
fun onHoge(foo: String, bar: Int)
}
// caller
var callback: CallBackListener? = null
callback?.onHoge("foo", 100)
// callee
val callback = object : CallBackListener {
override fun onHoge(foo: String, bar: Int) {
print("$foo : $bar")
}
}
これを typealias で。
typealias CallBackListener = (foo: String, bar: Int) -> Unit
// caller
var callback: CallBackListener? = null
callback?.invoke("foo", 100)
// callee
val callback = { foo, bar ->
print("$foo : $bar")
}
【Kotlin】 TypeAliasで関数リテラルに名前を付ける - Qiita
イベントハンドラ
例えば、RecyclerView でそれぞれのアイテムのViewHolder内のある要素のクリックイベントを拾いたい時、Activity(View)までが遠いですよね。
Activity(View)
↓↑
RecyclerViewAdapter
↓↑
ViewHolder
少しでも、コールバック記述をシンプルにして見通し良くしておきたいものです。
ここで Type Alias を使います。
typealias EventHandler
= (T) -> Unit
java - Kotlin: Use a lambda in place of a functional interface? - Stack Overflow
1. ViewHolder にハンドラー記述。クラスの外。
ItemViewHolder:
internal typealias ItemHandler = (Item) -> Unit
それを拡張して、ハンドラークラスを作ります。
invoke を override します。
ShareItemHandler:
internal class ShareItemHandler(
private val activity: Activity
) : ItemHandler {
override fun invoke(item: Item) {
IntentBuilder.from(activity)
.setType("text/plain")
.setChooserTitle("Share ${item.name} to ?")
.setText("${$item.name} ${item.address}")
.startChooser()
}
}
ClipboardCopyItemHandler:
internal class ClipboardCopyItemHandler(
private val context: Context
) : ItemHandler {
override fun invoke(item: Item) {
val clipboard = context.systemService<ClipboardManager>()
clipboard.primaryClip = ClipData.newPlainText(item.name, item.address)
}
}
2. Activity で そのインスタンスを生成して
RecyclerAdapter経由でViewHolder内にセットしていきます。
以下関係部分のみ抜粋。
MainActivity:
val onCopy = ClipboardCopyItemHandler(this)
val onShare = ShareItemHandler(this)
// ...
val layoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = layoutManager
val adapter = ItemAdapter(layoutInflater, onCopy, onShare)
recyclerView.adapter = adapter
ItemAdapter:
internal class ItemAdapter(
private val inflater: LayoutInflater,
private val onCopy: (Item) -> Unit,
private val onShare: (Item) -> Unit
) : RecyclerView.Adapter<ItemViewHolder>() {
// ...
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
val view = inflater.inflate(R.layout.item, parent, false)
return ItemViewHolder(view, onCopy, onShare)
}
ItemViewHolder:
internal typealias ItemHandler = (Item) -> Unit // ***
internal class ItemViewHolder(
private val root: View,
private val onCopy: ItemHandler
private val onShare: ItemHandler,
) : ViewHolder(root), OnClickListener, OnMenuItemClickListener {
// ...
override fun onClick(view: View) = when(view.id) {
R.id.copy -> onCopy(item!!)
R.id.share -> onShare(item!!)
else -> throw IllegalArgumentException("Unknown menu item: $menuItem")
}
なんだか素晴らしいですね。
RecyclerView利用時のテンプレートとして。
関連ワード: Android・AndroidStudio・Google・Kotlin・おすすめ・初心者・開発・event handler・typealias