处女男学Android(三)---Handler简介以及初步应用



前言



上一篇blog(处女男学Android(二)---Handler预习篇之Android的线程与UI)记录了Handler的存在价值,那么本篇就从实际应用的角度,通过实践来证明Handler是否能解决线程间的通信问题。



一、Handler简介和常用方法



Handler类的主要作用有两个:

1.在新启动的线程中发送消息。

2.在主线程中获取、处理消息。


那么问题是在什么时间发送消息?又在什么时间获取消息?这个时机如何把控?为了能让主线程即时的处理新线程发送的消息,显然只能通过回调的方式来实现,我们只要重写Handler类中处理消息的方法,当新线程发送消息时,消息会发送到与之关联的MessageQueue,而Handler会不断的从MessageQueue中获取并处理消息,这将导致Handler类中处理消息的方法被回调。所以我们需要在新的线程中发送消息(sendMessage),在Handler的handleMessage方法中接收、处理消息(这个方法位于主线程中)。上面两句话新手朋友可能会有疑问,在此关于Handler的工作机制暂时不做详细介绍,以实际应用为主,在后续的blog会介绍关于Handler、Looper、MessageQueue的工作机制和原理,这是关于Handler很重要的概念。本篇我们只做一个大致的了解,然后通过例子去掌握用法,说起来很简单,发送消息和接收消息,但这具体是通过哪些方法来实现的呢,我们来看看Handler的常用方法:


处女男学Android(三)---Handler简介以及初步应用_第1张图片


简单的熟悉了上述的方法,下面我们通过实例代码来验证以上的所有说法,首先简单的阐述一下这个例子的功能:

和上一篇blog中的例子相对应,同样的界面上有一个TextView和一个Button,点击Button更改TextView的颜色,并且追加一行文本,当然要做到程序不阻塞,并且是在新线程中。


Layout代码(second.xml):




    
    
    
    


Activity代码:


package com.example.handlertest;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class SecondActivity extends Activity {

	private TextView textView1;
	private Button button1;

	private Handler handler;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.second);
		textView1 = (TextView) findViewById(R.id.tv_textView1);
		handler = new MyHandler();
		button1 = (Button) findViewById(R.id.btn_changeText);
		button1.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Thread t = new WorkerThread();
				t.start();
			}
		});
	}

	// 定义一个WorkerThread
	class WorkerThread extends Thread {
		@Override
		public void run() {
			// 打印当前线程的Name
			System.out.println("WorkerThread--->"
					+ Thread.currentThread().getName());
			try {
				Thread.sleep(2 * 1000); // 模拟耗时任务休眠2s
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			String s = "\n has been changed !"; // 准备追加到TextView中的文本

			Message msg = handler.obtainMessage(); // 得到消息对象	
			msg.obj = s; // 通过obj属性携带数据
			handler.sendMessage(msg); // 发送消息,msg被发送到消息队列
		}

	}

	// 1.定义一个Handler类
	class MyHandler extends Handler {
		@Override
		public void handleMessage(Message msg) {
			// 打印当前线程的Name
			System.out.println("HandlerMessage--->"
					+ Thread.currentThread().getName());
			// TODO Auto-generated method stub
			super.handleMessage(msg);
			String s = (String) msg.obj; // 获取接收到的消息中的obj中的数据
			
			textView1.setText(textView1.getText() + s); 
			textView1.setTextColor(Color.RED); // 更改UI
		}

	}

}


通过上面的例子我们已经明白了Handler的使用方法,在WorkerThread中,通过handler的obtainMessage方法得到Message消息对象,通过Message对象的obj属性可以在消息中携带传递数据,然后通过sendMessage方法将消息发送出去,紧接着Handler通过其回调方法handlerMessage的就可以获取到消息,这个消息就是handleMessage方法中的参数Message对象,紧接着就可以处理消息了。



二、验证上述的两个说法



程序写好了,不知道是否像说的那么轻松自然,接下来我们运行一下程序来看看结果,并验证两个说法:

1.handlerMessage方法是否位于主线程?

2.UI线程是否会阻塞?


通过上一篇blog的记录我们应该知道不能在新线程中操作UI,不然会报错,上述程序有在handlerMessage中和WorkerThread中打印当前线程的Name,我们看一下运行之后并点击Button后的LogCat控制台:


处女男学Android(三)---Handler简介以及初步应用_第2张图片


根据时间我们可以看到,点击Button后,首先启动了WorkerThread,打印了其线程的Name为Thread-87,这个应该在我们的预料之内,线程睡眠了2s之后,紧接着执行了handleMessage方法,这就说明了只要在线程中发送消息,那么Handler的回调方法handleMessage就会即时的接收消息(其实是不断的从MessageQueue中读取消息,这里我们暂且不谈这些工作机制),handleMessage中打印的线程Name是main,没错这就是主线程了,所以我们在主线程中修改UI当然没有任何问题了。第一个说法没问题了,下面我们通过完整的运行效果看看第二个说法是否正确:


处女男学Android(三)---Handler简介以及初步应用_第3张图片


很明显UI线程没有被阻塞,效果也在我们的预期之内,点击Button,睡眠2s,成功更改界面,追加文本并修改颜色。



三、总结



本篇通过一个小例子记录了Handler的简单应用,介绍了如何通过Handler在子线程中给主线程发送消息,暂时没有介绍具体的工作机制和原理,由于我个人也是一个安卓开发新手,所以在相关原理和源码方面的解释不够专业和详尽,不过我还是会尽最大的努力去查阅资料,争取做到彻底理解之后再记录出来,因为刨根问底也是处女男的属性!




你可能感兴趣的:(Android基础,处女男玩Android,Handler)