【Kotlin/Android】HandlerとMessageの使い方!UI操作にデータ渡し

この記事からわかること
- Android Studio/KotlinのHandlerの使い方
- Messageオブジェクトでデータを渡す方法
- postメソッドとの違い
index
[open]
\ アプリをリリースしました /
環境
- Android Studio:Flamingo
- Kotlin:1.8.20
Handlerとは?
AndroidのHandler
とはスレッドと非同期で実行される処理に関連するタスクを管理するためのクラスです。Handler
を使用することでタイマーの設定や非同期的なタスクの処理、UIに関する作業をサブスレッドで行いたい場合などさまざまな機能を実現することができます。
詳細は以下の記事を参考にしてください。
バックグラウンドスレッドからUIを更新する
バックグラウンドスレッドで何かしらの重たい処理を実行しUIを更新したい場合はそのまま行なってしまうとアプリがクラッシュする原因になってしまいます。方法はいくつかありますが、Handler
を使用することでもバックグラウンドスレッドからUI操作を行う処理を実装することができます。
例えばLooper.getMainLooper()
でインスタンス化してHandler.post
メソッドを使用することで明示的にメインスレッドで処理を行うことが可能になります。この方法は内部的にRunnable
オブジェクトのrun
メソッドを実行しています。
var text: TextView = findViewById(R.id.textView)
// バックグラウンドスレッドに切り替える
GlobalScope.launch {
Log.e("スレッド", Thread.currentThread().toString()) // Thread[DefaultDispatcher-worker-1,5,main]
// 何かしらの重い処理
val handler = Handler(Looper.getMainLooper())
handler.post {
Log.e("スレッド", Thread.currentThread().toString()) // Thread[main,5,main]
// メインスレッド
text.text = "バックグラウンド" // 処理の結果など
}
}
Handler
で実装する方法はもう1つあり、それがMessage
オブジェクトを介した方法です。
sendMessageメソッドとMessageオブジェクトを使った方法
バックグラウンドスレッドからUI操作を行う方法としてhandleMessage
メソッドをオーバーライドしたHandler
クラスを作成します。このクラスは外部からメッセージを受信し、その内容によって処理を実装することが可能です。
private class MyHandler : Handler(Looper.getMainLooper()) {
companion object {
const val MSG_MAIN_HANDLER1 = 1
}
override fun handleMessage(msg: Message) {
var bundle = msg.data
var text = bundle.getString("key")
// 受信したメッセージの内容を処理する
when (msg?.what) {
MSG_MAIN_HANDLER1 -> {
Log.e("スレッド", Thread.currentThread().toString()) // Thread[main,5,main]
Log.e("---", text.toString())
}
}
}
}
handleMessage
メソッドに定義した処理を実行するにはsendMessage
メソッドを使用します。引数に渡せるのはMessage
オブジェクトとなっており、data
プロパティにBundle
形式でデータを持たせることが可能です。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var text: TextView = findViewById(R.id.textView)
GlobalScope.launch {
Log.e("スレッド", Thread.currentThread().toString()) // Thread[DefaultDispatcher-worker-1,5,main]
val handler = MyHandler()
val message = Message.obtain()
message.what = MyHandler.MSG_MAIN_HANDLER1 // メッセージを識別するためのコードを設定する
var bundle = Bundle()
bundle.putString("key", "Hello World!")
message.data = bundle
handler.sendMessage(message)
}
}
このように呼び出す側から何かしらのデータを渡すことができるようになり、処理も切り出すことができるので汎用性も高まります。
Messageオブジェクトとは?
Message
オブジェクトは異なるスレッド間でデータをやり取りするためのコンテナクラスです。基本的にはHandler
クラスと一緒に使用されます。
val message = Message.obtain()
message.what = MyHandler.MSG_MAIN_HANDLER1 // メッセージを識別するためのコードを設定する
var bundle = Bundle()
bundle.putString("key", "Hello World!")
message.data = bundle // Bundle形式でデータを渡す
プロパティには以下のものがあります。
- what:メッセージの整数型の識別子
- arg1:整数データを保持
- arg2:整数データを保持2
- obj:オブジェクトへの参照を含むオブジェクトデータ
- data:Bundle
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。