Android中的Handler, Looper, MessageQueue和Thread

直接在UI线程中开启子线程来更新TextView显示的内容,运行程序我们会发现,错 误android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.翻译过来就是:只有创建这个控件的线程才能去更新该控件的内容。

要想修改UI都必须在主线程中去做,我们不能直接在UI线程中去创建子线程,要利用消息机制:handler.


1)Looper: 一个线程可以产生一个Looper对象,由它来管理此线程里的MessageQueue(消息队列)。 Looper类用来管理特定线程内对象之间的消息交换(Message Exchange)。
2)Handler: 你可以构造Handler对象来与Looper沟通,以便push新消息到MessageQueue里;或者接收Looper从Message Queue取出)所送来的消息。
3) Message Queue(消息队列):用来存放线程放入的消息。 
4)线程:UIthread 通常就是main thread,而Android启动程序时会替它建立一个MessageQueue。
 在Android开发中,为了UI线程能及时响应需要避免在其中执行耗时操作,以防止界面假死甚至ANR。我们一般把耗时操作如下载,查询放在一个单独的线程中。这之后再将结果更新到UI界面。android平台在非UI线程中更新界面大致有以下几种方式
 Handler的处理过程运行在创建Handler的线程里


 一个Looper对应一个MessageQueue
 一个线程对应一个Looper
 一个Looper可以对应多个Handler

 不确定当前线程时,更新UI时尽量调用post方法

<span style="color:#333333;">public class MainActivity extends Activity {
	private Button button;
	private Handler handler;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		handler = new TimerHandler();
		WorkerThread wt = new WorkerThread();
		wt.start();
	}

	class WorkerThread extends Thread{
		@Override
		public void run(){
			while(true){
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				//创建消息
				Message msg = handler.obtainMessage();
				msg.arg1 = 10;
				msg.arg2 = 20;
				msg.obj = "zhangsan";
				//发送消息
				handler.sendMessage(msg);
			}
		}
	}
	
	class TimerHandler extends Handler{

		@Override
		public void handleMessage(Message msg) {
			//接收消息,此消息可以使对象
			int i = msg.arg1;
			int j = msg.arg2;
			String s = (String)msg.obj;
			Log.d("Handler", "收到消息:arg1:" + i +",arg2:" + j + ",s:" + s);
		}
		
	}

}</span>
一些耗时间的操作放在线程中去,通过Handler传递消息

public class MainActivity extends Activity {

	private TextView textView;
	private Button button;
	private Handler handler;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	
		handler = new NetworkHandler();
		
		textView = (TextView)findViewById(R.id.textViewId);
		button = (Button)findViewById(R.id.buttonId);
		button.setOnClickListener(new ButtonListener());
	}
	
	class ButtonListener implements OnClickListener{

		@Override
		public void onClick(View v) {
			NetworkThread nt = new NetworkThread();
			nt.start();
		}
		
	}
	
	class NetworkThread extends Thread{
		@Override
		public void run(){
			String url = "http://192.168.105.129:8081/data.html";
			Log.d("Handler02", "准备访问网路");
			//得到从网上下载的数据
			String data = getStringFromNetwork(url);
			//textView.setText(data);该行代码引起错误的原因是,不能够在Worker Thread当中修改控件的值
			//把数据放到handler中要用handler.obtainMessage();
			Message msg = handler.obtainMessage();
			msg.obj = data;
			handler.sendMessage(msg);
		}
	}
	
	class NetworkHandler extends Handler{
		@Override
		public void handleMessage(Message msg){
			//得到handler中数据把它赋给data
			String data = (String)msg.obj;
			textView.setText(data);
		}
	}

	//新建一个类,类型是String url
	public String getStringFromNetwork(String url){
		String result = "";
        //建个Http客户端访问网络下载数据
		HttpClient httpClient = new DefaultHttpClient();
		HttpGet httpGet = new HttpGet(url);
		try {
			HttpResponse response = httpClient.execute(httpGet);
			if(response.getStatusLine().getStatusCode() == 200){
				HttpEntity entity = response.getEntity();
				//连接已建立数据在entity中从entity中开始读数据
				BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent()));
				result = reader.readLine();
				Log.d("Handler02", "访问网络的结果是" + result);
				return result;
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

}

Looper的用法

class WorkerThread extends Thread{
		@Override
		public void run(){
			//生成Looper对象,该对象与当前线程对象组成了对应关系
			Looper.prepare();
			//生成Handler对象,并将其与刚刚生成Looper对象建立对应关系
			handler = new Handler(){
				@Override
				public void handleMessage(Message msg){
					Log.d("Handler", "收到来自主线程的消息");
				}
			};
			Looper.loop();
		}
	}

子线程中修改UI的方法

class WorkThread extends Thread{
		int i = 0 ;
		@Override
		public void run() {
			while(true){
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				i++;
				handler.post(new Runnable() {
					
					@Override
					public void run() {
						textView.setText(i + "");
					}
				});
			}
			



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值