phicdy devlog

Androidアプリ開発やその他技術系の記事をたまに書きます

AndroidとかiOSとかモバイル多め。その他技術的なことも書いていきます。

【Android】HanlderとMessageを使ってマルチスレッドの処理結果を受け取る

Androidアプリ内で重たい処理を行う場合、処理をメインスレッドで行うと処理が終わるまで画面が止まってしまう。
そのため、スレッドを分けて処理を行わせる。
その際に、処理結果を別スレッドから受け取るときの一つの方法としてHandlerとMessageを使う方法がある。

Handler handler = new Handler() {
	
    @override
    public void handleMessage(Message msg) {
        switch(msg.what) {
	    case 1:
	        // msg.objはObject型なのでキャストする必要がある
	        Log.d("Handler", (String)msg.obj);
	        break;
     	    default : 
    	        break;
        }
    }
}

class TaskTread extends Thread {
	private Handler handler;
	
	public TaskThread(Handler handler) {
		this.handler = handler;
	}
	
	@override
	public void run() {
		//重たい処理
		// ・・・
		
		Message msg = Message.obtain();
		// 実際にはマジックナンバーではなく値を決めておく
		msg.what = 1;
		
		// 結果がString型のresultにあると仮定
		msg.obj = result;
		handler.sendMessage(msg);
	}
}


まず、Handlerをメインスレッド内で宣言する。
Handlerはスレッドを超えてMessageクラスのオブジェクトを送受信することができる。
送信のメソッドは変更の必要がないので、受信を行うメソッドであるhandlerMessage(Message msg)のみoverrideする。

Handler handler = new Handler() {
	
    @override
    public void handleMessage(Message msg) {
        switch(msg.what) {
	    case 1:
	        // msg.objはObject型なのでキャストする必要がある
	        Log.d("Handler", (String)msg.obj);
	        break;
     	    default : 
    	        break;
    }
}

Messageはwhatというintのpublic変数を持っている。
送信の際にこのwhatを設定してあげることで、switch文などで送信先によって処理を分けることができる。
実際に受け取るデータはmsg.objに入っており、キャストしてデータを受け取る。

次に処理を行わせるスレッド(TaskTread)を宣言し、コンストラクタでHandlerを渡しておく。
このHandlerを利用して後にMessageをTaskThreadからメインスレッドに送信する。

class TaskTread extends Thread {
	private Handler handler;
	
	public TaskThread(Handler handler) {
		this.handler = handler;
	}
	
	@override
	public void run() {
		//重たい処理
		// ・・・
		
		Message msg = Message.obtain();
		// 実際にはマジックナンバーではなく値を決めておく
                msg.what = 1;
		
		// 結果がString型のresultにあると仮定
		msg.obj = result;
		handler.sendMessage(msg);
	}
}


TaskThreadで重たい処理を行わせた後、Messageの設定を行う。
MesageのインスタンスはMessage.obtain()で取得できる。
newでインスタンスを作ることもできるが、obtain()で行うことが推奨されており、効率がよい。

While the constructor of Message is public, the best way to get one of these is to call Message.obtain() or one of the Handler.obtainMessage() methods, which will pull them from a pool of recycled objects.

Message | Android Developers

次にwhatに送信先を識別するintを設定し、objに送信するデータを設定する。
そして最後にsendMessage(msg)でMessageを送信する。

sendMessage()を呼ぶとHabdlerのhanldeMessage()がメインスレッドで呼ばれ、処理結果を受け取ることができる。