Introduction to This Section
In the previous two sections, we studied the two event handling mechanisms in Android, and those are the only two types of event responses. This section explains Handler, which is used for message passing among UI components in an Activity. Many friends may know that Android, for thread safety, does not allow us to operate UI outside the UI thread. Many times, when we need to refresh the interface, we have to notify UI components to update via Handler! In addition to using Handler for interface updates, we can also use runOnUiThread() to update, or even more advanced event buses. Of course, here we only cover Handler: what Handler is, its execution flow, related methods, and the difference between using Handler in a child thread and in the main thread!
1. Learning Roadmap:

2. Introduction of the Handler Class:

3. Execution Flowchart of Handler:

Flowchart Analysis: Related Terms
- UI thread: This is our main thread. When the system creates the UI thread, it initializes a Looper object and also creates a MessageQueue associated with it.
- Handler: Its function is to send and process messages. If you want the Handler to work normally, there must be a Looper object in the current thread.
- Message: The message object that Handler receives and processes.
- MessageQueue: A message queue that manages Message in FIFO order. When initializing a Looper object, a MessageQueue associated with it is created.
- Looper: Each thread can only have one Looper, which manages the MessageQueue, continuously takes Message from it, and distributes them to the corresponding Handler for processing!
Simply put:
When our child thread wants to modify UI components in an Activity, we can create a new Handler object and send a message to the main thread through this object. The message we send will first wait in the main thread's MessageQueue; Looper takes it out in FIFO order, and then distributes it to the corresponding Handler for processing according to the `what` attribute of the message object.
4. Related Methods of Handler:
- void handleMessage(Message msg): The method for processing messages, usually meant to be overridden!
- sendEmptyMessage(int what): Send an empty message
- sendEmptyMessageDelayed(int what, long delayMillis): Send an empty message after a specified delay in milliseconds
- sendMessage(Message msg): Send a message immediately
- sendMessageDelayed(Message msg): Send a message after a specified delay in milliseconds
- final boolean hasMessage(int what): Check whether the message queue contains a message whose `what` attribute is the specified value. If the parameter is (int what, Object object): in addition to checking the `what` attribute, also check whether the Object attribute matches the specified object.
5. Usage Examples of Handler:
1) Handler Written in the Main Thread
In the main thread, because the system has already initialized a Looper object, we can directly create a Handler object and then send and process messages!
Code Example:A simple program that switches images periodically. It uses a Timer to periodically change the content displayed by the ImageView, thus creating a frame animation.
Running Effect:

Implementation Code:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/RelativeLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
tools:context="com.jay.example.handlerdemo1.MainActivity" >
<ImageView
android:id="@+id/imgchange"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" />
</RelativeLayout>
MainActivity.java:
public class MainActivity extends Activity {
//定义切换的图片的数组id
int imgids[] = new int[]{
R.drawable.s_1, R.drawable.s_2,R.drawable.s_3,
R.drawable.s_4,R.drawable.s_5,R.drawable.s_6,
R.drawable.s_7,R.drawable.s_8
};
int imgstart = 0;
final Handler myHandler = new Handler()
{
@Override
//重写handleMessage方法,根据msg中what的值判断是否执行后续操作
public void handleMessage(Message msg) {
if(msg.what == 0x123)
{
imgchange.setImageResource(imgids[imgstart++ % 8]);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ImageView imgchange = (ImageView) findViewById(R.id.imgchange);
//使用定时器,每隔200毫秒让handler发送一个空信息
new Timer().schedule(new TimerTask() {
@Override
public void run() {
myHandler.sendEmptyMessage(0x123);
}
}, 0,200);
}
}
2) Handler Written in a Child Thread
If the Handler is written in a child thread, we need to create a Looper object ourselves! The creation process is as follows:
1 )Call the Looper.prepare() method directly to create a Looper object for the current thread, and its constructor will create a matching MessageQueue.2 )Create a Handler object and override the handleMessage() method to process messages from other threads.3 )Call the Looper.loop() method to start the Looper.
Usage Example: Enter a number, calculate, and output all prime numbers within this range via Toast.
Implementation Code:main.xml:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="@+id/etNum"
android:inputType="number"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入上限"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="cal"
android:text="计算"/>
</LinearLayout>
MainActivity.java:
public class CalPrime extends Activity
{
static final String UPPER_NUM = "upper";
EditText etNum;
CalThread calThread;
// 定义一个线程类
class CalThread extends Thread
{
public Handler mHandler;
public void run()
{
Looper.prepare();
mHandler = new Handler()
{
// 定义处理消息的方法
@Override
public void handleMessage(Message msg)
{
if(msg.what == 0x123)
{
int upper = msg.getData().getInt(UPPER_NUM);
List<Integer> nums = new ArrayList<Integer>();
// 计算从2开始、到upper的所有质数
outer:
for (int i = 2 ; i <= upper ; i++)
{
// 用i处于从2开始、到i的平方根的所有数
for (int j = 2 ; j <= Math.sqrt(i) ; j++)
{
// 如果可以整除,表明这个数不是质数
if(i != 2 && i % j == 0)
{
continue outer;
}
}
nums.add(i);
}
// 使用Toast显示统计出来的所有质数
Toast.makeText(CalPrime.this , nums.toString()
, Toast.LENGTH_LONG).show();
}
}
};
Looper.loop();
}
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
etNum = (EditText)findViewById(R.id.etNum);
calThread = new CalThread();
// 启动新线程
calThread.start();
}
// 为按钮的点击事件提供事件处理函数
public void cal(View source)
{
// 创建消息
Message msg = new Message();
msg.what = 0x123;
Bundle bundle = new Bundle();
bundle.putInt(UPPER_NUM ,
Integer.parseInt(etNum.getText().toString()));
msg.setData(bundle);
// 向新线程中的Handler发送消息
calThread.mHandler.sendMessage(msg);
}
}
PS: This example is from "Crazy Android" ~
Summary of This Section
This section provides a brief analysis of Handler message passing in Android. We need to clearly distinguish the concepts of Handler, Message, MessageQueue, and Looper, as well as the difference between writing Handler in the main thread and in a child thread!