为何引入Handler?

为了解决多线程并发操作UI导致的线程安全问题,Android规定只允许在UI线程中修改UI,子线程若想修改UI可通过Handler机制解决。

如何理解Handler

Handler像是主线程的一个助手,负责处理其他子线程的消息(请求主线程更新UI),因为主线程很忙,不能即时处理,便让Handler将请求都放在一旁(消息队列里),主线程每隔一段时间就派Looper从消息队列取消息,并交给相应的Handler,Handler根据消息决定如何更新UI。 Handler处理机制

子线程调起Handler发送Message【1】至MessageQueue【2】。Message存储着修改UI用到的信息,MessageQueue是一个消息队列,缓存着多个Message。

主线程自动管理Looper,通过Looper定期轮询消息队列,取出Message【3】,分发给相应的Handler【4】。

Handler收到分发到的消息,进行处理,调用handlerMessage()方法【5】修改UI。

在使用中,我们可以通过重写handlerMessage方法来填写业务代码,如何根据接收到的Message来修改UI就是自己程序的业务了。

Untitled

Handler不同场景下的实例化

如果调用不带参构造器:Handler handler = new Handler(),那么这个handler会默认使用当前线程的looper。

而我们知道只有主线程可更新UI,所以如果想在子线程更新UI,可以选择在主线程无参实例化,或者选择在子线程通过Handler handler = new Handler(Looper.getMainLooper()) 实例化。

使用handler更新UI有多种方式:

  1. 主线程实例化时重写handlerMessage处理消息,子线程通过handler.sendMessage()发送消息。
  2. 主线程实例化,子线程调用handler.post方法,重写Runnable的run方法并交给handler处理。

Handler-handlerMessage-Sample

 public class MainActivity extends Activity {
     private TextView mTextView;
     
     //override handlerMessage
     Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
             if (msg.what == 0) {
                 mTextView.setText("...");
             } else if (msg.what == 1) {
                 mTextView.setText("###");
             }
         }
     };
  
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
         
         //child thread
         new Thread(new Runnable() {
             @Override
             public void run() {
                 Message msg = mHandler.obtainMessage();
                 msg.what = 1;
                 mHandler.sendMessage(msg);
             }
         }).start();
     }
 }

Handler-post-Sample

 public class MainActivity extends Activity {
     private TextView mTextView;
  
     //override handlerMessage
     Handler mHandler = new Handler();
  
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
  
         //child thread
         new Thread(new Runnable() {
             @Override
             public void run() {
                 mHandler.post(new Runnable() {
                     @Override
                     public void run() {
                         mTextView.setText("###");
                     }
                 });
             }
         }).start();
     }
 }

关于handler.post方法再说明一下,不同于第一种方法,调用post会将一个重写的Runnable封装成Message,调起Handler机制处理Message。主线程Looper去消息队列取出Message,调起Runnable的run方法更新UI。