android异步加载之Handler、AsyncTask(一)

Android中的异步加载有2种方式:(1)Handler+Message+Looper实现异步加载,更新UI;(2)利用AsyncTask异步加载类(抽象类)。

一、 Handler+Message+Looper基础
Handler+Meaasge+Looper也是android中的消息处理机制。因为android在子线程中是不能更新UI的,所以需要通过消息传递通知更新UI。这里写图片描述
(1) Handler:处理消息(只处理由自己发出的消息)和发送消息,将子线程中需要传递的消息数据,通过Message封装 ,再用Handler将消息加入消息队列MessageQueue(一个线程可以有多个Handler);
(2) Looper:Looper就是一个循环工作的线程,负责创建一个MessageQueue,然后进入一个无线循环体不断的从该MessageQueue中读取消息。(一个线程实例中只能有一个Looper(它是一个ThreadLocal),一个Looper实例也只有一个MessageQueue)。

1. Looper:线程循环工作
若要将一个线程创建为Looper线程,只需要在作如下修改,在线程的run方法中添加Looper.prepare()方法和Looper.loop()方法。

public class LooperThread extends Thread {
    @Override
    public void run() {
        // 将当前线程初始化为Looper线程
        Looper.prepare();

        // ...其他处理,如实例化handler

        // 开始循环处理消息队列
        Looper.loop();
    }
}

而Android的UI线程在Activity启动时就已经调用了Looper.prepare()和Looper.loop()方法,所以一般我们都是直接创建Handler实例就可以进行消息的传递。

class MyHandler extends Handler {
    @Override
    public void handleMessage(Message msg) {
        // 取出消息,更新UI…
    }
}

Looper类源码分析

public class Looper {
    // 每个线程中的Looper对象其实是一个ThreadLocal,即线程本地存储(TLS)对象
    private static final ThreadLocal sThreadLocal = new ThreadLocal();
    // Looper内的消息队列
    final MessageQueue mQueue;
    // 当前线程
    Thread mThread;
    // 。。。其他属性

    // 每个Looper对象中有它的消息队列,和它所属的线程
    private Looper() {
        mQueue = new MessageQueue();
        mRun = true;
        mThread = Thread.currentThread();
    }

    // 我们调用该方法会在调用线程的TLS中创建Looper对象
    public static final void prepare() {
        if (sThreadLocal.get() != null) {
            // 试图在有Looper的线程中再次创建Looper将抛出异常
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper());
    }
    // 其他方法
public static final void loop() {...}
//结束一个looper循环
public void quit(){...}
}

其中最重要的就是prepare()方法和loop()方法:
(1) prepare()方法
在该方法中先判断sThreadLocal是否为空,这个保证了在一个线程中只能包含一个Looper实例。若sThreadLocal不为空,则将一个Looper的实例放入sThreadLocal中。
在new Looper()方法中创建一个MessageQueue消息队列。
(2) loope()方法

public static void loop() {
    //获得Looper实例
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    //获得Looper创建的MessageQueue队列
    final MessageQueue queue = me.mQueue;
    ...

    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }
        ...
        //处理消息
        msg.target.dispatchMessage(msg);
        ...
        //释放资源
        msg.recycle();
    }
}

其中myLooper()返回sThreadLocal存储的Looper实例:

public static Looper myLooper() {
    return sThreadLocal.get();
}

获取Looper中的MessageQueue消息队列,再通过for循环获取Message,使用msg.target.dispatchMessage(msg)把消息发给msg的target(其实就是Handler)的dispatchMessage()方法去处理,最后释放资源。

总结:Looper的作用在于与当前线程进行绑定,这样保证一个线程只有一个Looper实例,同时一个Looper实例也只能创建一个MessageQueue消息队列;loop方法不断地从MessageQueue消息队列中获取消息,再交给消息的target的dispatchMessage()方法来处理消息。

2. Handler:异步消息处理
在Looper中已经创建了一个MessageQueue并且可获取到了消息,那Looper内的消息从哪里来的呢?loop方法中调用target.dispatchMessage()方法又是怎么样处理消息的呢?Handler的作用开始体现了,我们都是直接实例化Handler:

mHandler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        // 取出消息,更新UI…
    }
};

Handler类的源码分析

public class handler {

    final MessageQueue mQueue;  // 关联的MQ
    final Looper mLooper;  // 关联的looper
    final Callback mCallback; 
    ....// 其他属性
    public Handler() {
        ....//其它代码

        // 默认将关联当前线程的looper
        mLooper = Looper.myLooper();
        // looper不能为空,即该默认的构造方法只能在looper线程中使用
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        // 重要!!!直接把关联looper的MQ作为自己的MQ,因此它的消息将发送到关联looper的MQ上
        mQueue = mLooper.mQueue;
        mCallback = null;
    } 
    // 其他方法
}

(1)Looper和Handler关联
其中Handler和Looper通过Looper.myLooper()进行关联,再获取Looper的MessageQueue这样就和Handler进行关联。
(2)在android应用中,我们创建Handler之后,将需要传递的消息数据用Message进行封装,再通过Handler的sendMessage()方法或者sendEmptyMessageDelayed()方法将消息发送出去,发出去之后怎么将消息存入MessageQueue呢?

public final boolean sendMessage(Message msg){
    return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
    Message msg = Message.obtain();
    msg.what = what;
    return sendMessageDelayed(msg, delayMillis);
}

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发送消息之后,最后到enqueueMessage()方法中将消息存储到MessageQueue里。

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

msg.target = this就标记了在Looper中所用到的target为Handler。
进一步queue.enqueueMessage方法:

final boolean enqueueMessage(Message msg, long when) {

      Message p = mMessages;

      if (p == null || when == 0 || when < p.when) {
         msg.next = p;
         mMessages = msg;
      }
      else {

             Message prev = null;
             while (p != null && p.when <= when) {
                    prev = p;
                    p = p.next;
             }
             msg.next = prev.next;
             prev.next = msg;
      }
    ...//
}

从代码中可以看出,从Handler发出来的消息是按照时间存储到MessageQueue中的。
(3)Looper中的msg.target.dispatchMessage(msg)方法
先看方法dispatchMessage()

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        // 如果message设置了callback,即runnable消息,处理callback!
        handleCallback(msg);
    } else {
        // 如果handler本身设置了callback,则执行callback
        if (mCallback != null) {
             /* 这种方法允许让activity等来实现Handler.Callback接口,避免了自己编写handler重写handleMessage方法. */
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        // 如果message没有callback,则调用handler的钩子方法handleMessage
        handleMessage(msg);
    }
}

最后调用了handleMessage()方法,该方法是子类中进行消息处理必须重写的方法。
总结(梳理Looper->Handler):
(1)Looper.prepare()在线程中准备一个Looepr实例,并在该实例中创建一个MessageQueue消息队列(有且只有一个);
(2)Looper.loop()让当前线程进入一个无线循环,不断从MessageQueue中读取信息,让后回调msg.target.dispatchMessage()方法;
(3)Handler的构造方法会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue相关联;
(4)Handler的sendMessage方法,会给msg的target赋值为handler自身,然后将消息加入MessageQueue队列中;
(5)在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法,在此对消息进行处理。

下一节记录AsyncTask.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只打杂的码农

你的鼓励是对我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值