【Android基础知识】Handler、Message、Looper的关系

为什么只能在UI线程进行更新UI

最根本的目的就是为了解决多线程并发问题。

  假如在一个Activity中,有多个线程去更新UI,并且都没有加锁,那么会产生什么问题?

更新界面错乱

  如果对更新UI的操作都进行加锁处理的话又会产生什么问题?

性能下降

为了处理上面的问题,android给我们提供了一套更新UIhandler机制,我们不用关心多线程问题,只需要去遵循这样的机制就可以了。

 

Handler的基本概念

提供了异步的线程处理。

有很多的操作不能放在onCreate里面,如下载操作等耗时比较长的操作。我们把这些操作放在一些单独的线程里面。

Android 更新UI

错误的更新方式:

在非UI线程中更新UI

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myText = (TextView)findViewById(R.id.text);
        new Thread(){
        	@Override
        	public void run() {
        		try {
					Thread.sleep(2000);
					myText.setText("hello android");
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
        	}
        }.start();
    }


正确的使用方式,使用handler

Handler.post()方法直接执行了线程的run()方法,其实这个线程和Activity在同一个线程中。并没有调用start方法,没有启动新线程。

public class MainActivity extends Activity {
	private TextView myText ;
	private Handler handler = new Handler();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myText = (TextView)findViewById(R.id.text);
        new Thread(){
        	@Override
        	public void run() {
        		//这里使用post方法后这个线程是运行在UI线程中的
        		handler.post(new Runnable() {
					
					@Override
					public void run() {
						try {
							Thread.sleep(2000);
							myText.setText("hello android");
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				});
        	}
        }.start();
    }
}

使用Callbackmessage进行拦截

需要引入包import android.os.Handler.Callback;

//handler Callback 方法,可以对message进行拦截,如果返回true则拦截
	private Handler handler2 = new Handler(new Callback() {
		//这个方法可以对接收到的message进行拦截
		@Override
		public boolean handleMessage(Message msg) {
			Toast.makeText(getApplicationContext(), "1", Toast.LENGTH_SHORT).show();
			return false;
		}
	}){
		@Override
		public void handleMessage(Message msg) {
			Toast.makeText(getApplicationContext(), "2", Toast.LENGTH_SHORT).show();
		}
	};

在UI线程创建Handler

UI线程默认会创建一个Looper,Handler在调用构造方法的时候会默认去关联这个Looper对象,所以在主线程中创建一个Handler的方法是
Handler handler = new Handler(){
			@Override
			public void handleMessage(Message msg) {
				// TODO Auto-generated method stub
				super.handleMessage(msg);
			}
		};

在子线程创建Handler

子线程中没有Looper对象,所以我们要自己去获取一个Loopoer对象,并且需要调用Looper.loop()方法,轮循处理消息。
public class LooperThread extends Thread {
    @Override
    public void run() {
        // 将当前线程初始化为Looper线程
        //当前线程里就产生了一个Looper对象,在创建Handler的时候会和其关联起来
        Looper.prepare();
        
        // ...其他处理,如实例化handler
        
        // 开始循环处理消息队列,这是一个死循环,有消息就处理,没有消息就阻塞
        Looper.loop();
    }
}

Android 消息处理机制: Handler   Message   Looper

Handler封装了消息的发送,(主要包括消息发送给谁,一般发送给自己)

Looper

1.内部包含一个消息队列也就是MessageQueue,所有的Handler发送的消息都走向消息队列。

2.Looper.Loop()方法,就是一个死循环,不断从MessageQueue取消息,如果有消息就处理,没有消息就阻塞。

MessageQueue ,就是一个消息队列,可以添加消息,并处理消息。

Handler也很简单,内部会跟Looper进行关联,也就是说在Handler的内部可以找到Looper,找到了Looper也就找到了MessageQueue,在Handler发送消息时其实是向MessageQueue队列中发送消息。

总结:handler负责发送消息,Looper负责接收Handler发送的消息,并把消息发送给handler自己,MessageQueue就是一个存储消息的容器。

Handler发送消息

有了handler之后,我们就可以使用 post(Runnable), postAtTime(Runnable, long), postDelayed(Runnable,long),sendEmptyMessage(int),sendMessage(Message), sendMessageAtTime(Message, long)sendMessageDelayed(Message, long)这些方法向MQ上发送消息了。光看这些API你可能会觉得handler能发两种消息,一种是Runnable对象,一种是message对象,这是直观的理解,但其实post发出的Runnable对象最后都被封装成message对象了

1 message.target为该handler对象,这确保了looper执行到该message时能找到处理它的handler,即loop()方法中的关键代码

 

Handler处理消息

// 处理消息,该方法由looper调用
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            // 如果message设置了callback,即runnable消息,处理callback!
            handleCallback(msg);
        } else {
            // 如果handler本身设置了callback,则执行callback
            if (mCallback != null) {
                 /* 这种方法允许让activity等来实现Handler.Callback接口,避免了自己编写handler重写handleMessage方法。
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            // 如果message没有callback,则调用handler的钩子方法handleMessage
            handleMessage(msg);
        }
    }
    
    // 处理runnable消息
    private final void handleCallback(Message message) {
        message.callback.run();  //直接调用run方法!
    }
    // 由子类实现的钩子方法
    public void handleMessage(Message msg) {
}

HandlerThread的使用

注意:Handler属于哪个线程不是看它在哪里创建的,而是看其关联的Looper对象在哪个线程

实现子线程向主线程互相发送消息,子线程中可以处理耗时任务
/*
 * 如何向子线程发送消息
 */
public class FourthActivity extends Activity implements OnClickListener{
	private Button sendButton;
	private Button stopButton;
	
	private HandlerThread thread;
	private Handler threadHandler;
	//创建一个和主线程相关的handler
	private Handler handler = new Handler(){
		@Override
		public void handleMessage(android.os.Message msg) {
			//给子线程发送一个消息
			Message message = new Message();
			message.what =1;//这里需要设置和removeMessage方法中的参数一致,不然停止不了
			threadHandler.sendMessageDelayed(message, 1000);
			Log.i("meng","main handler");
		}
	};
	@Override
	public void onCreate(android.os.Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.four);
		sendButton = (Button)findViewById(R.id.send_message);
		stopButton = (Button)findViewById(R.id.stop_message);
		sendButton.setOnClickListener(this);
		stopButton.setOnClickListener(this);
	    thread = new HandlerThread("handler thread");
	    thread.start();
	    //创建一个子线程的handler
	    threadHandler = new Handler(thread.getLooper()){
	    	@Override
	    	public void handleMessage(android.os.Message msg) {
	    		Message message = new Message();
	    		message.what = 1;
	    		//每隔1秒给主线程发送一个消息
	    		handler.sendMessageDelayed(message, 1000);
	    		Log.i("meng","thread handler");
	    	}
	    };
	}
	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch (v.getId()) {
		case R.id.send_message:
			//调用
			handler.sendEmptyMessage(1);
			break;
		case R.id.stop_message:
			handler.removeMessages(1);
			break;
		default:
			break;
		}
	}
}
精彩博客链接:  http://blog.csdn.net/lmj623565791/article/details/47079737/





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值