Android: How to send a message from a Thread to a Handler

[toc]

As a quick example of how to use a Thread with a basic Handler in an Android application, the following code creates a view where the text in the TextView is updated to show the current date and time when the Button is tapped.

Java source code

First, here’s the Java source code for a file class named ThreadHandlerActivity:

import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.os.Handler;
import android.os.Message;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import com.alvinalexander.todo.R;

public class ThreadHandlerActivity extends Activity {

    private static final String MSG_KEY = "yo";

    /**
     * perform the action in `handleMessage` when the thread calls
     * `mHandler.sendMessage(msg)`
     */
    @SuppressLint("HandlerLeak")
    private final Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            Bundle bundle = msg.getData();
            String string = bundle.getString(MSG_KEY);
            final TextView myTextView = (TextView)findViewById(R.id.myTextView);
            myTextView.setText(string);
        }
    };

    private final Runnable mMessageSender = new Runnable() {
        public void run() {
            Message msg = mHandler.obtainMessage();
            Bundle bundle = new Bundle();
            bundle.putString(MSG_KEY, getCurrentTime());
            msg.setData(bundle);
            mHandler.sendMessage(msg);
        }
    };

    private String getCurrentTime() {
        SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss MM/dd/yyyy", Locale.US);
        return dateFormat.format(new Date());
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_thread_example);
        final Button button = (Button) findViewById(R.id.myButton);
        button.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                handleButtonClick(v);
            }
        });
    }

    public void handleButtonClick(View view) {
        new Thread(mMessageSender).start();
    }

    @Override
    protected void onPause() {
        super.onPause();
        //TODO not sure if this is needed for this use case
        mHandler.removeCallbacks(mMessageSender);
    }

}

XML layout file

Next, here’s the layout XML for the view, from a file named activitythreadexample.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/myTextView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:height="32dp"
        android:text="TextView" />

    <Button
        android:id="@+id/myButton"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button" />

</LinearLayout>

The app

Here’s what this little app looks like in an Android emulator:

Android thread, runnabler, and handler example

Discussion

Please note that this source code is heavily based on the now-old book, Android 4.4 App Development. I was just looking into threads and handlers in Android last night, and this is a relatively simple example of how to send a message from a thread/runnable to a handler.

Note that I had to add the @SuppressLint annotation to this code. I don’t know much about handlers yet, so I need to look into why that is needed. I do know that Android Studio is telling me that the handler should be declared as a static field. (Adding the annotation isn’t 100% necessary, but it’s a nice reminder that there’s a potential problem here.)