android中handler消息机制的原理,用法

本文详细介绍了Android中Handler消息机制的原理及其主要组成部分,包括Message、Handler、MessageQueue和Looper等。并通过实例展示了如何在主线程和子线程间进行消息传递,以及一些常用的扩展方法。

Android消息传递之Handler消息机制
前言:
无论是现在所做的项目还是以前的项目中,都会遇见线程之间通信、组件之间通信,目前统一采用EventBus来做处理,在总结学习EventBus之前,觉得还是需要学习总结一下最初的实现方式,也算是不忘初心吧,这也是今天来学习总结Handler消息机制的一个原因。

Handler机制产生背景

一个Android应用程序被创建的时候都会创建一个UI主线程,但是有时我们会有一些比较耗时的操作,为了防止阻塞UI主线程,我们会将耗时的操作放到子线程中进行处理,处理完之后操作UI,但是Android不允许子线程操作UI,违背了Android单线程模型的原则(即 Android UI操作并不是线程安全的并且这些操作必须在UI线程中执行),所以Android通过Handler消息机制来实现线程之间的通讯。

Handler机制主要角色

Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。

Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。

MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。

Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。

Thread:线程,负责调度整个消息循环,即消息循环的执行场所。

举例:
主线程定义Handler

Handler mHandler = new Handler() {
	        @Override
	        public void handleMessage(Message msg) {
	            super.handleMessage(msg);
	            switch (msg.what) {
	                case 0:
	                    //完成主界面更新,拿到数据
	                    String data = (String) msg.obj;
	                    textView.setText(data);
	                    break;
	                default:
	                    break;
	            }
	        }
	        
子线程发消息,通知Handler完成UI更新


 private void getDataFromNet() {
	        new Thread(new Runnable() {
	            @Override
	            public void run() {
	                //耗时操作,完成之后发送消息给Handler,完成UI更新;
	                mHandler.sendEmptyMessage(0);
	
	                //需要数据传递,用下面方法;
	                Message msg = new Message();
	                msg.obj = "网络数据";//可以是基本类型,可以是对象,可以是List、map等;
	                mHandler.sendMessage(msg);
	            }
	        }).start();
	 }

这里实例下主线程发消息给子线程的代码(一般情况下是主线程通知子线程干活了采用到)

public class LooperThreadActivity extends Activity{
 /** Called when the activity is first created. */
 
 private final int MSG_HELLO = 0;
 private Handler mHandler;
  
 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
  new CustomThread().start();**//新建并启动CustomThread实例**
   
  findViewById(R.id.send_btn).setOnClickListener(new OnClickListener() {
    
   @Override
   public void onClick(View v) {//点击界面时发送消息
    String str = "hello";
    Log.d("Test", "MainThread is ready to send msg:" + str);
    mHandler.obtainMessage(MSG_HELLO, str).sendToTarget();**//主线程发送消息到CustomThread实例**
   }
  });
 }
  
 class CustomThread extends Thread {
  @Override
  public void run() {
   //建立消息循环的步骤
   Looper.prepare();**//1、初始化Looper**
   mHandler = new Handler(){**//2、绑定handler到CustomThread实例的Looper对象**
    public void handleMessage (Message msg) {**//3、定义处理消息的方法**
     switch(msg.what) {
     case MSG_HELLO:
      Log.d("Test", "CustomThread receive msg:" + (String) msg.obj);
     }
    }
   };
   Looper.loop();**//4、启动消息循环**
  }
 }
}

这里要注意一点当主线程发送给子线程,当界面消失时一定要释放子线程不然会线程堵塞
/获取当前 Looper 对象 myLooper = Looper.myLooper(); (要全局然后在子线程中获取)最后在界面ondestory中myLooper.quit();

注意:针对与主线程和子线程间的通信有一点要特别注意,那么就是谁发消息给谁(谁处理消息就用谁的handler发送)。如果是子线程发送给主线程那就简单很多,因为主线程是默认会有handler对象和Looper对象的,如果是主线程发送给子线程那么hander必须在子线程声明,并且实例子线程的Looper在处理计划任务,在未来执行某任务,使用的方法为postXXX();**

示例:
主线程定义Handler

private Handler mHandler=new Handler();
子线程提交任务更新UI
private void getDataFromNet() {
			     new Thread(new Runnable() {
			            @Override
			            public void run() {
			                //耗时操作,完成之后提交任务更新UI
			                final String data = "网络数据";
			                mHandler.post(new Runnable() {
			                    @Override
			                    public void run() {
			                        textView.setText(data);
			                    }
			                });
			            }
			        }).start();
	 }

Handler机制扩展
为了更加方便的使用Handler消息机制,Android也提供了几种扩展方式,内部实现都是基于Handler消息机制 Activity.runOnUiThread(Runnable)

private void getDataFromNet() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                //耗时操作,完成之后提交任务更新UI
                final String data = "网络数据";
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText(data);
                    }
                });
            }
        }).start();
	 }

View.post(Runnable)

 private void getDataFromNet() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                //耗时操作,完成之后提交任务更新UI
                final String data = "网络数据";
                textView.post(new Runnable() {
                    @Override
                    public void run() {
                        textView.setText(data);
                    }
                });
            }
        }).start();
}

5.使用AsyncTask代替Thread

 private void getDataFromNet() {
        MyTask task = new MyTask();
        task.execute();
    }

    private class MyTask extends AsyncTask {
        //后台线程执行时
        @Override
        protected Object doInBackground(Object... params) {
            ////耗时操作,
            String data = "网络数据";
            return data;
        }

        //后台线程执行结束后的操作,其中参数result为doInBackground返回的结果
        @Override
        protected void onPostExecute(Object result) {
            super.onPostExecute(result);
            textView.setText((String) result);
	        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值