Android Handler

    当咱们建立的Service、Activity以及Broadcast均是一个主线程处理,这里咱们能够理解为UI线程。可是在操做一些耗时操做时,好比I/O读写的大文件读写,数据库操做以及网络下载须要很长时间,为了避免阻塞用户界面,出现ANR的响应提示窗口,这个时候咱们能够考虑使用Thread线程来解决。    java

    不少初入Android或Java开发的新手对Thread、Looper、Handler和Message仍然比较迷惑,衍生的有HandlerThread、java.util.concurrent、Task、AsyncTask也是只知其一;不知其二。android

Handler简单的总结:

一. postInvalidate()

    以使用postInvalidate()方法在线程中来处理在线程中的刷新一个View为基类的界面,其中还提供了一些重写方法好比postInvalidate(int left,int top,int right,int bottom) 来刷新一个矩形区域,以及延时执行,好比postInvalidateDelayed(long delayMilliseconds)或postInvalidateDelayed(long delayMilliseconds,int left,int top,int right,int bottom) 方法,其中第一个参数为毫秒程序员

二.Handler

     固然推荐的方法是经过一个Handler来处理这些,能够在一个线程的run方法中调用handler对象的 postMessage或sendMessage方法来实现,Android程序内部维护着一个消息队列,会轮训处理这些,若是你是Win32程序员能够很好理解这些消息处理,不过相对于Android来讲没有提供 PreTranslateMessage这些干涉内部的方法。数据库

    使用Handler以前,咱们都是初始化一个实例,好比用于更新UI线程,咱们会在声明的时候直接初始化,或者在onCreate中初始化Handler实例。网络

    Handler的构造方法异步

    看其如何与MessageQueue联系上的,它在子线程中发送的消息(通常发送消息都在非UI线程)怎么发送到MessageQueue中的。async

public Handler() {  
    this(null, false);  
} 
 
public Handler(Callback callback, boolean async) {  
    if (FIND_POTENTIAL_LEAKS) {  
        final Class<? extends Handler> klass = getClass();  
        if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) 
                && (klass.getModifiers() & Modifier.STATIC) == 0) {  
            Log.w(TAG, "The following Handler class should be static or leaks might occur: "
                 + klass.getCanonicalName());  
        }  
    }  
    mLooper = Looper.myLooper();  //获取当前线程保存的Looper实例,
                                  //保证了handler的实例与咱们Looper实例中MessageQueue关联上了。
    if (mLooper == null) {  
        throw new RuntimeException("Can't create handler inside thread that has not 
            called Looper.prepare()");  
    }  
    mQueue = mLooper.mQueue;  //获取这个Looper实例中保存的MessageQueue(消息队列)
    mCallback = callback;  
    mAsynchronous = async;  
}

    查看sendMessage方法源码发现ide

    1.sendMessage()->sendMessageDelayed();  函数

    2.sendEmptyMessageDelayed()->sendMessageDelayed();oop

    3.sendMessageDelayed()->sendMessageAtTime();

    1/2/3展转反则最后调用了sendMessageAtTime(),sendMessageAtTime()内部有直接获取MessageQueue而后调用了enqueueMessage方法,咱们再来看看此方法:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {  
   msg.target = this;  
   if (mAsynchronous) {  
       msg.setAsynchronous(true);  
   }  
   return queue.enqueueMessage(msg, uptimeMillis);  
}

    enqueueMessage中首先为meg.target赋值为this,【若是你们还记得Looper的loop方法会取出每一个msg而后交给msg,target.dispatchMessage(msg)去处理消息】,也就是把当前的handler做为msg的target属性。最终会调用queue的enqueueMessage的方法,也就是说handler发出的消息,最终会保存到消息队列中去。

    如今已经很清楚了Looper会调用prepare()和loop()方法,在当前执行的线程中保存一个Looper实例,这个实例会保存一个MessageQueue对象,而后当前线程进入一个无限循环中去,不断从MessageQueue中读取Handler发来的消息。而后再回调建立这个消息的handler中的dispathMessage方法,下面咱们赶快去看一看这个方法:

public void dispatchMessage(Message msg) {  
    if (msg.callback != null) {  
        handleCallback(msg);  //这是一个空方法,由于消息的最终回调是由咱们控制的,
                    //咱们在建立handler的时候都是复写handleMessage方法,而后根据msg.what进行消息处理。
    } else {  
        if (mCallback != null) {  
            if (mCallback.handleMessage(msg)) {  
                return;  
            }  
        }  
        handleMessage(msg);  
    }  
}

    Handler 建立实例:

private Handler mHandler = new Handler(){  
    //复写handleMessage方法
    public void handleMessage(android.os.Message msg){  
        switch (msg.what) {  
        case value:  
            break;  
        default:  
            break;  
        }  
    };  
};

 

三. Looper    

    其实Android中每个Thread都跟着一个Looper,Looper能够帮助Thread维护一个消息队列,可是Looper和Handler没有什么关系,咱们从开源的代码能够看到Android还提供了一个Thread继承类HanderThread能够帮助咱们处理,在HandlerThread对象中能够经过getLooper方法获取一个Looper对象控制句柄,咱们能够将其这个Looper对象映射到一个Handler中去来实现一个线程同步机制,Looper对象的执行须要初始化Looper.prepare方法同时推出时还要释放资源,使用Looper.release方法。应用程序的主线程中会始终存在一个Looper对象,在主线程中能够直接建立Handler对象,而在子线程中须要先调用Looper.prepare()才能建立Handler对象。

 

    Android Looper简介

四.Message    

对于Android中Handler能够传递一些内容,经过Bundle对象能够封装String、Integer以及Blob二进制对象,咱们经过在线程中使用Handler对象的sendEmptyMessage或sendMessage方法来传递一个Bundle对象到Handler处理器。对于Handler类提供了重写方法handleMessage(Message msg) 来判断,经过msg.what来区分每条信息。将Bundle解包来实现Handler类更新UI线程中的内容实现控件的刷新操做。相关的Handler对象有关消息发送sendXXXX相关方法以下,同时还有postXXXX相关方法,这些和Win32中的道理基本一致,一个为发送后直接返回,一个为处理后才返回 .

五. java.util.concurrent对象分析

对于过去从事Java开发的程序员不会对Concurrent对象感到陌生吧,他是JDK 1.5之后新增的重要特性做为掌上设备,咱们不提倡使用该类,考虑到Android为咱们已经设计好的Task机制,这里不作过多的赘述,相关缘由参考下面的介绍:

六. AsyncTask:

在Android中还提供了一种有别于线程的处理方式,就是Task以及AsyncTask,从开源代码中能够看到是针对Concurrent的封装,开发人员能够方便的处理这些异步任务。

 Android AsyncTask

七.Handler发送消息:

        new出一个Message对象,而后可使用setData()方法或arg参数等方式为消息携带一些数据,再借助Handler将消息发送出去就能够了。

new Thread(new Runnable() {  
    @Override  
    public void run() {  
        Message message = new Message();  
        message.arg1 = 1;  
        Bundle bundle = new Bundle();  
        bundle.putString("data", "data");  
        message.setData(bundle);  
        handler.sendMessage(message);  
    }  
}).start();

        Handler中提供了不少个发送消息的方法,其中除了sendMessageAtFrontOfQueue()方法以外,其它的发送消息方法最终都会展转调用到sendMessageAtTime()方法中。

        sendMessageAtTime()方法接收两个参数,其中msg参数就是咱们发送的Message对象,而uptimeMillis参数则表示发送消息的时间,它的值等于自系统开机到当前时间的毫秒数再加上延迟时间,若是你调用的不是sendMessageDelayed()方法,延迟时间就为0,而后将这两个参数都传递到MessageQueue的enqueueMessage()方法中。

八.MessageQueue  

   它是一个消息队列,用于将全部收到的消息以队列的形式进行排列,并提供入队和出队的方法。这个类是在Looper的构造函数中建立的,所以一个Looper也就对应了一个MessageQueue。

    MessageQueue并无使用一个集合把全部的消息都保存起来,它只使用了一个mMessages对象表示当前待处理的消息。MessageQueue的对象调用enqueueMessage(msg, uptimeMillis)方法将消息加入到消息队列,返回bool类型的值。所谓的入队其实就是将全部的消息按时间来进行排序,这个时间是sendMessageAtTime(Message msg, long uptimeMillis)中的uptimeMillis参数。具体的操做方法就根据时间的顺序调用msg.next,从而为每个消息指定它的下一个消息是什么。固然若是你是经过sendMessageAtFrontOfQueue()方法来发送消息的,它也会调用enqueueMessage()来让消息入队,只不过期间为0,这时会把mMessages赋值为新入队的这条消息,而后将这条消息的next指定为刚才的mMessages,这样也就完成了添加消息到队列头部的操做。

九.除了发送消息以外,咱们还有如下几种方法能够在子线程中进行UI操做:

    1. Handler的post()方法

    2. View的post()方法,就是调用了Handler中的post()方法

    3.Activity的runOnUiThread()方法

    Android 子线程中进行UI操做(非发送消息)

十.Handler 、 Looper 、Message之间的关系:

    其实Looper负责的就是建立一个MessageQueue,而后进入一个无限循环体不断从该MessageQueue中读取消息,而消息的建立者就是一个或多个Handler 。

    一、首先Looper.prepare()在本线程中保存一个Looper实例,而后该实例中保存一个MessageQueue对象;由于Looper.prepare()在一个线程中只能调用一次,因此MessageQueue在一个线程中只会存在一个。

    二、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,而后回调msg.target.dispatchMessage(msg)方法。

    三、Handler的构造方法,会首先获得当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。

    四、Handler的sendMessage方法,会给msg的target赋值为handler自身,而后加入MessageQueue中。

    五、在构造Handler实例时,咱们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。

十一.Handler的post方法建立的线程和UI线程之间的关系:

mHandler.post(new Runnable() {  
    @Override  
    public void run()  {  
        Log.e("TAG", Thread.currentThread().getName());  
        mTxt.setText("yoxi");  
    }  
});

    而后run方法中能够写更新UI的代码,其实这个Runnable并无建立什么线程,而是发送了一条消息,下面看源码:

public final boolean post(Runnable r)  {  
  return  sendMessageDelayed(getPostMessage(r), 0);  
}  
private static Message getPostMessage(Runnable r) {  
  Message m = Message.obtain();  
  m.callback = r;  
  return m;  
}

    能够看到,在getPostMessage中,获得了一个Message对象,而后将咱们建立的Runable对象做为callback属性,赋值给了此message.

    注:产生一个Message对象,能够new  ,也可使用Message.obtain()方法;二者均可以,可是更建议使用obtain方法,由于Message内部维护了一个Message池用于Message的复用,避免使用new 从新分配内存。

public final boolean sendMessageDelayed(Message msg, long delayMillis){  
    if (delayMillis < 0) {  
        delayMillis = 0;  
    }  
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  
}

 

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {  
    MessageQueue queue = mQueue;  
    if (queue == null) {  
        RuntimeException e = new RuntimeException(this + " sendMessageAtTime() called with no mQueue");  
        Log.w("Looper", e.getMessage(), e);  
        return false;  
    }  
    return enqueueMessage(queue, msg, uptimeMillis);  
}

    最终和handler.sendMessage同样,调用了sendMessageAtTime,而后调用了enqueueMessage方法,给msg.target赋值为handler,最终加入MessagQueue.

    能够看到,这里msg的callback和target都有值,可是执行dispatchMessage方法:

public void dispatchMessage(Message msg) {  
    if (msg.callback != null) {  //若是不为null,则执行callback回调,也就是咱们的Runnable对象。
        handleCallback(msg);  
    } else {  
        if (mCallback != null) {  
            if (mCallback.handleMessage(msg)) {  
                return;  
            }  
        }  
        handleMessage(msg);  
    }  
}

十二.Handler中obtainMessage与new Message的区别:

在handler.obtainMessage()的参数是这样写的:

Message android.os.Handler.obtainMessage(int what, int arg1, int arg2, Object obj)
Parameters
what  Value to assign to the returned Message.what field.
arg1  Value to assign to the returned Message.arg1 field.
arg2  Value to assign to the returned Message.arg2 field.
obj  Value to assign to the returned Message.obj field.

obtainmessage()是从消息池中拿来一个msg 不须要另开辟空间。

new须要从新申请,效率低,obtianmessage能够循环利用;

obtainMessage写法:

1.mHandler.obtainMessage(what, arg1, 0, object).sendToTarget();
2.Message msg = mHandler.obtainMessage();
  msg.what = what;
  msg.obj = object;
  msg.sendToTarget();

message 从handler 类获取,从而能够直接向该handler 对象发送消息。

New Message写法:

Message msg=new Message();  
msg.arg1=i;  
handler.sendMessage(msg);

直接调用 handler 的发送消息方法发送消息。

两种写法中Message都可以setData(Bundle bundle)

相关文章
相关标签/搜索