欢迎转载,但请标明出处:http://blog.csdn.net/android_for_james/article/details/51173944
如果有多个线程并发操作UI,就有可能会导致线程安全问题,为了解决这个问题,Android制定了一个规则:只允许UI线程修改Activity里的UI,如果我们想动态的改变界面组件的属性值就需要用到Handler。例如我们在执行下载图片任务时,显然这是一个耗时任务,我们需要一个新线程来完成这个下载任务,当任务完成后我们需要将图片绘制到界面上,这时就需要Hanlder来发送一个消息给ImageView告诉它需要绘制图片。
我们先来看一下我这个例子程序的运行效果图:
首先我们需要知道Handler,Looper,MessageQueue这三者是做什么的
1.Handler:它具有两个功能,一个是发消息和处理消息。
2.Looper:它是一个循环器,作用是用来循环取出MessageQueue中的消息。
3.MessageQueue:它是一个消息队列,既然是队列当然具有先进先出原则,用来管理Message。
三者的关系是:
Handler发送消息给----->MessageQueue(不过MessageQueue是由Looper来管理的,因此在做这步操作时,在线程应该已经有一个Looper对象)----->Looper(循环读取MessageQueue中的Message)----->Handler(处理Looper读取到的消息)
这里我们不禁会产生疑问,我们在主线程中使用Handler时并没有涉及到MessageQueue和Looper呀~我们知道他们之间的关系干什么?
这个问题的答案就是在主UI线程中,系统已经为我们初始化了一个Looper对象了,因此我们直接创建Handler对象即可发送消息,还有一个需要我们知道的是,每一个线程都只有一个与之对应的Looper,因此当我们自己的线程类中新建的Handler发送消息时就不能使用主线程中的Looper,那么这时我们的线程类就需要一个自己的Looper。
解决上述问题的方法是:
class MyThread extends Thread
{
public Handler myhandler;
@Override
public void run() {
super.run();
//创建该线程的Looper对象
Looper.prepare();
myhandler=new Handler()
{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
//循环器开始循环
Looper.loop();
}
}
我来介绍一下我这个例子程序有什么内容
1.介绍了Handler的四种发送消息的用法分别是:
(1)post()
(2)postDelayed()(实现图片动态循环显示)
(3)sendMessage()
(4)sendEmptyMessage()
2.在线程类中新建自己的Handler并在主线程中调用
布局文件很简单,就是两个TextView一个ImageView所以我就不给布局代码了
下面我们来看具体代码:
public class MainActivity extends ActionBarActivity {
private ImageView image;
private TextView text;
private TextView text2;
private int images[]={R.drawable.a1,R.drawable.a2,R.drawable.a3};
private int index=0;
private MyRunnable myRunnable=new MyRunnable();
private MyThread zyThread;
private Handler handler=new Handler();
private Handler handler2=new Handler()
{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Toast.makeText(MainActivity.this,msg.obj.toString(),Toast.LENGTH_LONG).show();
}
};
//要想使用handler的postDelayed()方法必须有一个runnable对象
class MyRunnable implements Runnable
{
@Override
public void run() {
index++;
index=index%images.length;
image.setImageResource(images[index]);
text.setText("第"+(index+1)+"张图片");
handler.postDelayed(myRunnable,1500);
}
}
class MyThread extends Thread
{
public Handler myhandler;
@Override
public void run() {
super.run();
//创建该线程的Looper对象
Looper.prepare();
myhandler=new Handler()
{
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Toast.makeText(MainActivity.this,"新线程tdhandler中的message信息是"+msg.obj.toString(),Toast.LENGTH_LONG).show();
}
};
//循环器开始循环
Looper.loop();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initEvent();
//使用postDelayed()发送数据,这时数据会根据后面的值延迟
handler.postDelayed(myRunnable, 1500);
//启动新线程
zyThread=new MyThread();
zyThread.start();
try {
zyThread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//在新线程中使用线程自己的handler发送数据
Message message2=new Message();
message2.obj="我是tdThread线程中的message";
zyThread.myhandler.sendMessage(message2);
new Thread()
{
@Override
public void run() {
super.run();
try {
Thread.sleep(1000);
//直接使用post发送数据
handler.post(new Runnable() {
@Override
public void run() {
text2.setText("使用post方法更新数据");
}
});
//使用sendmessage发送数据
Message message=new Message();
message.obj="使用sendmessage发送数据";
handler2.sendMessage(message);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
public void initEvent()
{
image=(ImageView)findViewById(R.id.imageView);
text=(TextView)findViewById(R.id.textView);
text2=(TextView)findViewById(R.id.textView2);
}
}
依然是在最后我用红字标出需要注意的问题
1.在新线程中创建Handler时必须先创建Looper,即先调用Looper.prepare()为当前线程创建一个Looper实例,并创建配套的MessageQueue,再去创建Handler对象,最后调用
Looper.loop来开始循环读取消息
2.handleMessage方法一般用于重写操作
希望对大家有所帮助,欢迎转载但要标明出处,谢谢!!!
有什么不足的地方可以留言给我我会尽快回复并改正!!!
欢迎关注我的博客:http://blog.csdn.net/android_for_james