出于性能优化的考虑,Android的UI操作并不是线程安全的,这意味着如果有多个线程并发操作UI,可能导致线程安全问题。为了解决这个问题,Android制定了一条简单的规则:只允许UI线程修改Activity的UI组件。
当一个程序第一次启动时,Activity会同时启动一条主线程,主线程主要负责处理与UI相关的事件,如用户的按键操作、用户触摸屏幕的事件及屏幕绘制事件,并把相关的事件分发到对应的组件进行处理。所以主线程通常又被叫做UI线程。
Android的消息传递机制是另一种形式的“事件处理”,这种机制主要为解决Android应用的多线程问题---Android平台只允许UI线程修改Activity里的UI组件,这就会导致新启动的线程无法动态改变界面组件的属性值。但实际在开发中,尤其是涉及动画的游戏开发中,需要让新启动的线程周期性的改变界面组件的属性值,这就需要借助于Handler的消息传递机制。
Handler类主要作用有两个:
---在新启动的线程中发送消息;
---在主线程中获取、处理消息。
上面的说法看上去很简单,似乎只分成两步:在新线程中发送消息,然后再主线程中获取并处理消息即可。但过程中涉及一个问题,新启动的线程何时发送消息?主线程又何时处理消息?时机如何控制?
为了解决处理消息问题,只能通过回调的方式来实现---重写Handler类的handleMessage()方法。 当新启动的线程发送消息时,消息会发送到与之关联的MessageQueue,而Handler会不断从MessageQueue中获取并处理消息--这将导致Handler中处理消息的方法被回调。
计算质数实例:
package com.example.calprime; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private static final String DATA_NUM = "num"; private static final String RESULT_KEY = "result_key"; EditText editText; MyThread myThread; TextView result; class MyThread extends Thread { public Handler mHandler; @Override public void run() { // super.run(); Looper.prepare(); mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == 0x110) { int num = msg.getData().getInt(DATA_NUM); Listnums = new ArrayList<>(); //计算从2开始到num的所有质数 for (int i = 2; i <= num; i++) { //用i除以从2开始,到i的平方根的所有数 boolean isadd = true; for (int j = 2; j <= Math.sqrt(i); j++) { //如果可以整除,则不是质数 if (i != 2 && i % j == 0) { isadd = false; continue; } } if (isadd) { nums.add(i); } } //Toast显示 Toast.makeText(MainActivity.this, nums.toString(), Toast.LENGTH_LONG).show(); Message message = new Message(); message.what = 0x111; Bundle bundle = new Bundle(); bundle.putString(RESULT_KEY, nums.toString()); message.setData(bundle); mUiHandler.sendMessage(message); } } }; Looper.loop(); } } Handler mUiHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == 0x111) { result.setText(msg.getData().getString(RESULT_KEY)); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); editText = findViewById(R.id.edit); result = findViewById(R.id.result); myThread = new MyThread(); myThread.start(); } public void cal(View view) { Message message = new Message(); message.what = 0x110; Bundle bundle = new Bundle(); bundle.putInt(DATA_NUM, Integer.parseInt(editText.getText().toString())); message.setData(bundle); myThread.mHandler.sendMessage(message); } } 运行结果: