菜鸟来解释线程中的循环者Looper读取消息队列

安卓中的Looper使用就是用来给线程创建一个循环,类似while或for循环等。

public class LooperDemo extends Activity {

	private String tag = "LooperDemo";
	private Handler handler;
	private int num = 0;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		startThread();
		findViewById(R.id.textView).setOnClickListener(
				new View.OnClickListener() {

					@Override
					public void onClick(View v) {
						Message msg = new Message();
						Bundle data = new Bundle();
						num++;
						data.putString("looper", "I am from main thread : "+ num);
						msg.setData(data);
						handler.sendMessage(msg);
					}
				});
	}

	protected void startThread() {
		new Thread(new Runnable() {

			@Override
			public void run() {
				Looper.prepare();
				handler = new Handler() {
					@Override
					public void handleMessage(Message msg) {
						super.handleMessage(msg);
						Bundle bundle = msg.getData();
						Log.i(tag, "" + bundle.getString("looper"));
						Toast.makeText(LooperDemo.this,
								"[" + bundle.getString("looper")+"]",
								Toast.LENGTH_SHORT).show();
						if(num > 5){
							// 退出之后再发会报错
							Looper.myLooper().quit();
						}
					}

				};
				SystemClock.sleep(1000);
				Log.i(tag, "线程启动");
				Looper.loop();
			}
		}).start();
		;
	}
}
上面的运行结果就是
线程启动
I am from main thread : 1
I am from main thread : 2
I am from main thread : 3

可以看出“线程启动”只打印一次,但是 I am from main thread : n 就是每次按下按键的时候触发打印一次,这告诉我们一个故事:被 Looper.prepare(); 和 Looper.loop(); 包围的部分不表明就是循环的一部分。要在Handler里面的,同时 Handler 又别这两语句包围,才能实现循环监听,类似注册一个广播接收器BroadcastReceiver。上面的例子就是一个子线程接收UI线程的消息并可以处理数据,也可以说是线程之间的通信,就是子线程跟子线程也是可以混在一起的互相发消息的。

安卓的消息处理机制中存在着3个核心类Looper,Handler和Message,这3个核心又是为Message Queue(消息队列)而工作的,Message Queue又被封装到Looper里面。
这摆明了Looper在消息处理中的重要位置;直接翻译就是循环者。那就是用来进行循环,与while,for循环相等,但是Looper常用在线程中。

Looper说白了就是给线程添加一个消息队列,然后进入循环等待,等待有消息到来时唤起线程来处理消息,直到线程结束为止。通常的主线程是不会被开发者看到,但是UI线程还是有一个由Looper带来的消息队列,主线程的消息循环就会一直进行,处理用户事件,直到触发onDestroy;

如果,我们需要新建一个线程,并且这个线程要能够循环处理其他线程发来的消息事件,或者需要长期与其他线程进行复杂的交互,这时就需要用到Looper来给线程建立消息队列。

使用Looper也非常的简单,它的方法比较少,最主要的有四个:
public static prepare();
public static myLooper();
public static loop();
public void quit();


在每个线程的run()方法中的最开始调用Looper.prepare(),这是为线程初始化消息队列;
调用Looper.myLooper()获取此Looper对象的引用。这不是必须的,但是prepare()之后才能做相关的操作;
在run()方法中添加Handler来处理消息;
添加Looper.loop()调用,这是让线程的消息队列开始运行,可以接收消息了。
调用Looper.quit()退出消息循环;

需要注意的是当一个线程的消息循环已经退出后,不能再给其发送消息,否则会有异常抛出"RuntimeException: Handler{4051e4a0} sending message to a Handler on a dead thread"。所以,建议在Looper.prepare()后,调用Looper.myLooper()来获取对此Looper的引用,一来是用于终止(quit()必须在对象上面调用); 另外就是用于接收消息时检查消息循环是否已经退出(如上例)。发送消息的时候也要进行判断循环体是否已经退出,否则也会报错异常说没有Handler处理消息


说一下用法:
1当子线程需要接收UI的数据再进行相关处理的时候可以Looper来进行接收消息队列的消息;
2当UI线程需要一直监听某些事件,比如按键处理等,可以Looper,因为程序一启动就给UI线程建立了一个Looper来监听来自界面或者其他的一些消息;
3子线程之间需要通信也可以使用Looper来监听消息队列的消息,因为消息队列可以是某一线程放入的消息;

初步了解Looper的用法,暂时记录,留以后增加修改;



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值