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

この記事からわかること

  • Android Studio/KotlinHandler使い方
  • Messageオブジェクトデータ渡す方法
  • postメソッドとの違い

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

公式リファレンス:Handler

環境

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オブジェクト

Messageオブジェクトは異なるスレッド間でデータをやり取りするためのコンテナクラスです。基本的にはHandlerクラスと一緒に使用されます。

val message = Message.obtain()
message.what = MyHandler.MSG_MAIN_HANDLER1 // メッセージを識別するためのコードを設定する
var bundle = Bundle()
bundle.putString("key", "Hello World!")
message.data = bundle // Bundle形式でデータを渡す

プロパティには以下のものがあります。

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index