Android笔记——Handler

来源:互联网 发布:javiewer差不多的软件 编辑:程序博客网 时间:2024/06/10 10:20

一、Handler类的作用

由于主线程只能处理UI相关的事件,比如说按键、用户触屏以及屏幕绘图事件等。所以当我们处理比较耗时的任务的时候,需要另起线程。但是Android规定,只有主线程能够修改Activity里面的UI组件,这样就会导致我们新起的线程中无法动态改变UI组件的属性值。为了处理Android中多线程的问题,我们就借助Handler类来处理了。

所以说Handler类的作用主要有两个:1是在新线程中发送消息;2是在主线程中获取、处理消息。

对于开发者来说,我们只需要重写Handler中的handleMessage(Message msg)方法就可以了,当新线程启动线程发送消息的时候,消息会发送到与之关联的MessageQueue队列中,然后Handler就会不断从MessageQueue中取出消息然后执行handleMessage()方法,这就会导致Handler类中的handleMessa()方法被回调。


二、Handler类工作的原理

首先我们来认识一下Looper、Message、MessageQueue这三个东西。

1.Looper:每个线程有且只能拥有一个Looper。它的loop方法负责读取MessageQueue中的消息,读到信息之后就把消息交给发送该消息的Handler进行处理了。

2.Message:Handler接收和处理的消息对象。

3.MessageQueue:消息队列,它采用的是先进先出的方式进行管理Message。程序创建Looper对象的时候会在它的构造器中创建MessageQueue对象。

我们知道Handler的作用有两个:发送消息和处理消息。当程序使用Handler发送消息的时候,被Handler发送的消息就会送到指定的MessageQueue队列中。也就是说,如果想要Handler正常工作的话,那么MessageQueue是一定不能少的,也就是说在Handler所在的线程中一定得有一个MessageQueue。然而MessageQueue是通过Looper来创建的,所以说要想要有MessageQueue,就必须在Handler所在的线程中有一个Looper对象。对于Looper对象,可以分为两种情况:

I:主UI线程中,系统在开始的时候已经初始化了一个Looper对象,所以我们不用自己新创建Looper对象了。因此在主线程中我们直接创建Handler类即可,然后使用Handler来进行消息的发送和接收。

II:子线程,子线程是我们自己创建的线程,因此它不会自动帮你初始化Looper对象,所以需要我们自己创建Looper对象,并启动它。由于Looper对象的构造器是private的,所以我们不能直接通过构造器创建Looper对象,但是可以通过Looper对象调用它的prepare()方法来创建。(prepare()方法可以保证每个线程只有一个Looper)

上面说了那么多细节的东西,总结下来就是Handler的工作原理就是(以子线程和UI线程的通信为例,在主线程中创建Handler):当子线程有消息要处理并用到UI组件的时候,就要在子线程中调用Handler消息传送的方法(sendMessage、sendEmptyMessage等)将消息传送到MessageQueue队列中。然后在主线程中Handler便会取出MessageQueue队列中的消息并调用handleMessage(Message msg)方法来处理子线程传过来的消息。

而如果需要在子线程使用Handler的话,那么流程和主线程和子线程的过程差不多,只是需要在负责处理消息的子线程中创建Looper和启动Looper。


三、Looper的具体应用。

1.主UI线程使用Handler。

public class HandlerTest extends Activity{String tag = "Handler";@Overridepublic void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.main);Log.i(tag, "Main Thread:" + Thread.currentThread().getId());final Handler myHandler = new Handler(){@Overridepublic void handleMessage(Message msg){// 如果该消息是本程序所发送的if (msg.what == 0x1233){Log.i(tag, "deal the message:" + Thread.currentThread().getId());}}};// 定义一个计时器,让该计时器周期性地执行指定任务new Timer().schedule(new TimerTask(){@Overridepublic void run(){// 发送空消息myHandler.sendEmptyMessage(0x1233);Log.i(tag, "Child Thread in sendMessage:" + Thread.currentThread().getId());}}, 0, 1200);}}

从上图可以看到,当程序启动的时候会在日志输出主线程的ID,然后子线程在一段时间内向UI线程发送一个空消息并输出子线程的ID,最后主线程会使用HandleMessage来处理子线程发来的消息。日志输出的线程的ID很好的说明了Handler的工作流程。


2.子线程使用Handler。

<pre name="code" class="java">public class MainActivity extends ActionBarActivity {private Button btn;String tag = "Handler";MyThread myThread;class MyThread extends Thread{public Handler mhandler;public void run(){Looper.prepare();//创建Loopermhandler = new Handler(){@Overridepublic void handleMessage(Message msg) {// TODO Auto-generated method stubsuper.handleMessage(msg);Log.i(tag, "Deal msg:" + Thread.currentThread().getId());Log.i(tag, "传来的消息是:" + msg.what);/*在这里写入你需要处理的程序,注意一般要子线程处理的是比较耗时的操作。 * 因为在主线程中不能处理耗时的操作。这里只演示子线程使用Handler,并无具体操作 */Toast.makeText(MainActivity.this, "这里是处理哦!", Toast.LENGTH_SHORT).show();}};Looper.loop();//要启动Looper!}}    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);                btn = (Button) findViewById(R.id.btn);                myThread = new MyThread();        myThread.start();                btn.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View arg0) {// TODO Auto-generated method stubMessage msg = new Message();msg.what = 0x123;Log.i(tag, "Send Msg:" + Thread.currentThread().getId());myThread.mhandler.sendMessage(msg);}                });    }}

从上图可以看到,子线程使用Handler其实都差不多的。只是要创建Looper和启动Looper。


0 0
原创粉丝点击