初步窥探android线程间通讯:Handler, Looper, MessageQueue的使用方法

昨天看了mars老师的视频。学习了android线程间的通讯,初步熟悉了Handler, Looper, MessageQueue的用法,趁着还没忘写下来吧。

Handler、Looper、MessageQueue的作用:

Handler:它有两个作用——发送消息(sendMessage)和处理消息(handleMessage);程序使用Handler发送消息至消息队列中去,也可以处理由Looper发送过来的消息;创建Handler对象时必须重写handleMessage方法;

Looper:不断的从消息队列中取出消息对象,并调用Handler的handlerMessage方法处理消息;如果队列中没有消息对象,则其处于阻塞等待状态;

Message:Handler处理和发送的消息对象;

MessageQueue:消息队列,采用先进先出的模式(FIFO)来管理Message;

线面通过两种方式来展现线程之间的通讯,第一种是从子线程向UI程发送消息;第二种是从UI线程向主线程发送消息。

一、子线程向UI线程发送消息,代码如下:

package cui.handler_test02;


import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
/**
 * 实现线程之间的通讯
 * 从子线程向UI线程发送消息"我来自另一个线程",UI线程接受到消息后打印在TextView中
 * 布局文件为一个TextView和Button,很简单就不呈现了
 * @author pramb
 *
 */
public class MainActivity extends Activity {
	
	TextView textView;
	Button button;
	//创建一个Handler的全局变量
	Handler handler;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		button = (Button) findViewById(R.id.button);
		textView = (TextView) findViewById(R.id.textView);
		handler = new MyHandler();
		
		button.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				//按下按钮后启动子线程
				new Thread(new MyThread()).start();
			}
		});
	}

	class MyHandler extends Handler{
		//必须要重写handlerMessage方法,处理Looper传来的消息,因为怎么处理消息对象时你自己的事
		@Override
		public void handleMessage(Message msg) {
			//收到由子线程传来的消息后先打印出当前操作的线程名字,然后打印出
			//传来的消息,并且更新到textView中
			System.out.println(Thread.currentThread().getName());
			System.out.println((String)msg.obj);
			textView.setText((String)msg.obj);
		}
	}
	//创建线程类
	class MyThread implements Runnable{

		@Override
		public void run() {
			//获取一个消息对象,至于为什么这样获取,API上说这样获取更好,
			//可以自己查看一下obtainMessage()方法的介绍
			Message msg = handler.obtainMessage();
			//所发送的消息
			String s = "我来自另一个线程";
			//复制给Message的属性
			msg.obj = s;
			//向消息队列中发送消息对象
			handler.sendMessage(msg);
			//打印当前操作线程的名字
			System.out.println(Thread.currentThread().getName());
		}
	}
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}
}
二、由UI线程向子线程发送消息,和第一个有点不同:




package cui.handler_test03;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
/**
 * 实现UI线程与子线程之间的通讯,要注意与上一个实现方式不同
 * 主要功能是按下按钮后先打印当前操作的线程的名字,并发送消息对象到子线程,子线程拿到
 * 消息对象后,打印当前操作的线程的名字
 * @author yonglin
 *
 */
public class MainActivity extends Activity {
	
	Button button;
	Handler handler;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		button = (Button) findViewById(R.id.button);
		new Thread(new MyThread()).start();
		//点击按钮后,打印当前操作的线程,然后向子线程发送消息
		button.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				System.out.println(Thread.currentThread().getName());
				Message msg = handler.obtainMessage();
				handler.sendMessage(msg);
			}
		});
	}

	class MyThread implements Runnable{

		@Override
		public void run() {
			//创建Looper对象
			Looper.prepare();
			//重写handleMessage方法
			handler = new Handler(){
				@Override
				public void handleMessage(Message msg) {
					//接受由UI线程发送过来的消息,并打印当前操作的线程名字
					System.out.println(Thread.currentThread().getName());
				}
			};
			//不断的从消息队列中取出消息对象,并调用handleMessage(Message msg)处理
			Looper.loop();
		}
		
	}
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		if (id == R.id.action_settings) {
			return true;
		}
		return super.onOptionsItemSelected(item);
	}
}



上图为打印结果

两种方式的程序结构有很大的不同,仔细看一下,至于为什么不同,可以参考一下源代码,我也不大清楚;还有一点很重要:原则上不能在子线程中操作UI控件,否则会报错!其实线程间通讯我感觉就是:A线程想向B线程发送消息的话,A先把消息传入消息队列,Looper把消息从消息队列中取出,再传给B,应该就是这个意思~~~

第一次写博客,也不大会写,技术还又菜,多多包涵哈!





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值