Android之handler介绍

来源:互联网 发布:地方台直播软件 编辑:程序博客网 时间:2024/04/30 02:44


handler字面意思是处理者,其实我们在学习编程的时候,很多单词从字面意思就可以猜出一二。那么这个处理者都处理些什么呢??有什么用呢?安卓开发中,一个对象处理完一些数据需要通知另一个对象继续处理后面逻辑的时候,就需要在两个对象之间通信,比如一个异步任务下载数据,下载完成的时候我们要告知UI线程更新view,这个时候我们可以使用接口回调,也可以发广播,这些都能做到(如果你告诉我用AsynTask,那你赢了~~因为这根本不是一回事)。如果这么一件小事你就用到广播,这就好比你叫你一个朋友吃饭,本来打个电话就可以搞定的事,你偏偏要去电台打个广告,让她在广告中得知你要叫她吃饭,未免也太小题大做了。这个时候我们完全可以用Message的方式,发个短信告诉她“hi,晚上一起吃个饭呗~~~”。那么handler如何使用呢?


先来看看handler是通信机制是怎么样的,要说清楚这个,我们来想想,发送消息需要用到哪些东西,首先必须要有一个消息对象,就是发送的具体内容,其次要有一个处理消息的对象,用来把消息发出去和接收消息,还要有一个运输的对象,扮演一个快递员的身份,有了这些最基本的东西才能是这个通信机制运行起来。ok,那么他们具体在安卓中是什么呢?下面一一做一个介绍。

消息对象:Message类,也就是消息的载体,一般通过handler.obtainMessage()或者Message.obtain()取得这个对象。

处理对象:Handler类,用来发送消息和接收消息并处理。

快递员:Looper类,在一堆消息中分离出消息发送到对应的处理对象里面。


那么又出现了一个新的词“一堆消息”,这一堆消息又是什么东西呢?Google在设计安卓的时候就考虑到了这个问题,何不把消息放到一个消息队列里面,这样集中处理也不至于太乱,所以就出现了一个消息队列(MessageQueen),把消息放在这个队列里面。不知道你们有没有考虑前面获取消息对象的时候,我们用的obtain这个词,他是直接拿过来的,那么开始肯定是有的,那么我们还没有消息对象,他是如何出来的呢???其实这个问题谷歌早就考虑到了,解决这个问题就出现了一个消息池(messagePool),有了一池子的消息对象,我们自然是想怎么用就直接拿来用。ok,说了这么多,你们可能看晕了~不知所云呐,又是姑娘又是吃饭还有池子,额~~~~~~~~~那么我就先来说说他运行的步骤吧。


首先在一个线程中只有一快递员,也就是那个Looper,Looper负责整个维护着MessageQueen,当一个Message对象被从消息池中取出来,并且赋予其使命的时候,就会把其放到消息队列里(MessageQueen),然后Looper把队列里第一个(队列遵循FIFO,也就是先进先出的单词缩写)消息对象取出来,送给消息处理者(Handler),Handler调用自己的handlerMessage方法,处理送来的赋予使命的Message,单处理完之后就把这个Message对象扔进消息池里面,这样才不会使消息池没有可用的消息对象(消息池一般不会低于5个可用的消息对象),如果队列里面还有有待使命的消息,looper就不停的取不停的送,这样就形成了一个循环,整个个机制就有条不紊的运行起来啦~~~~~~~~~~


ok,下面就来说说具体怎么使用这个机制,在一个线程中使用这个的步骤:

1、调用Looper.prepare(),把Looper和这个线程绑定(还记得一个线程只能有一个Looper吗?)

2、创建一个Handler对象,可以使用匿名内部类(这有一个内存泄露的问题,具体下面分析),也可以自定义一个类

3、在需要的地方获取一个消息对象,然后调用handler.sendEmptyMessage()发送这个消息。

4、在调用Looper.prepare()的方法末尾调用Looper.loop();

那么有的人可能要问了,我使用的时候没有用Looper那两个方法呐,怎么也可以呢???其实你那是在主线程中使用的,如果在别的线程那么直接用立马挂掉~~那么主线程为什么就不需要呢?这是因为主线程在底层已经帮我们调用了,所以不需要我们自己动手了,这里有一个问题,因为这个handler是运行在UI线程里面的,所以不要在这个线程里面做耗时操作会阻塞UI线程。ok,说了这么多,真的是该动手敲敲代码的时候,下面就用一个例子把这个知识点做一个演示。


子线程给主线程发消息:

<span style="font-size:14px;">handler = new MyHandler();// 其它线程给主线程发消息new Thread(new Runnable() {@Overridepublic void run() {// 获取到消息对象Message m = handler.obtainMessage();m.obj = "我是子线程";handler.sendMessage(m);}}).start();</span>
使用步骤:在主线程实例化handler,然后把这个handler传到子线程,在子线程中直接用这个handler发消息就可以在主线程中收到消息。


主线程给子线程发消息:

这种方式的时候,handler需要在子线程的run方法里面实例化,不然handler不能与该线程的Looper绑定,还有就是因为涉及到线程同步问题,所以需要使用到锁,要不然在主线程中获取到的handler基本是空指针。

<span style="font-size:10px;">public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);MyThread myThread = new MyThread();myThread.start();Handler handler = myThread.getHandler();Message msg = handler.obtainMessage();msg.obj = "我是主线程发送的消息";handler.sendMessage(msg);}class MyThread extends Thread {private Handler handler;private Object mSyn = new Object();// 加个同步保证初始化完成@Overridepublic synchronized void run() {super.run();Looper.prepare();synchronized (mSyn) {handler = new Handler(Looper.myLooper()) {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);Log.e("", msg.obj.toString());}};mSyn.notifyAll();}Looper.loop();}// 提供一个方法供其它线程获取到本线程的handlerpublic Handler getHandler() {synchronized (mSyn) {if (handler == null) {try {mSyn.wait();} catch (InterruptedException e) {e.printStackTrace();}}return handler;}}}}</span>


扫描关注我的微信公众号:


其余的自己给自己发消息就不演示了,太简单了。ok,handler的使用大概就是这个样子,有什么不清楚的,或者发现我说的哪里不对的地方,欢迎给我留言~~~~~~~~~最后附上Demo下载:Demo下载

1 0
原创粉丝点击