イベントハンドラとラムダ

おさらい


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利用時のテンプレートとして。


あの Jake Wharton さんが伝授する Android Studio を高速化する方法

直接は関係ないような気がしますが

「Kotlinを使ったら Android Studio が遅くなった」

という疑問に対して、神と呼ばれる Jake Wharton さんがコメントしています。

「プラグイン捨てれ」

I find the IDE slower when adding any plugin. Especially ones which provide a great deal of functionality such as an entire language support.

Go to preferences > plugins > and disable everything you don't need. I disabled

Android APK Support
Android Games
Android NDK
App Links Assistant
CVS
EditorConfig
Firebase (all of them)
GitHub
Google (all of them)
hg4idea
Settings repository
Subversion integration
Task management
Terminal
Test recorder
TestNG
YAML

Goes real fast now.

JakeWharton comments on Android Studio slower when using Kotlin

本体や各ウインドウの起動などかなり高速化されます。

Kotlin や Google や RxJava など多岐に渡るオープンソースプロジェクトに深く関わる Jake さんが必要ないプラグインが私たち小市民に必要なわけがありません。

一回も使ったことがないプラグインが多くあるのは間違いありません。

他の多機能アプリやソフトウェアにも同様のことがいえます。

確認してみてはいかがでしょうか。


【Android Studio】メニューバーをAndroidStudioに移動する

Mac OSのメニューバーにメニューが表示されて、他アプリのアイコンが表示できなくなって困ることがあります。

Android Studio内に移動しましょう。

[Help] - [Edit Custom Properties...]


# custom Android Studio properties

# メニューを Android Studio ウィンドウに表示
apple.laf.useScreenMenuBar=false

動画内1分23秒付近で説明されています。

ファイルの実態は以下のようです。

~/Library/Preferences/AndroidStudio3.0/idea.properties