美文网首页
Looper,handlerThread

Looper,handlerThread

作者: MDZZ灭顶之灾12138 | 来源:发表于2018-09-22 18:19 被阅读5次

主线程(ActivityThread)启动的过程中会调用Looper.prepareMainLooper(),Looper.loop()。将当前线程初始化为application's main looper,存放到sMainLooper。
Looper.class:

private static Looper sMainLooper;  // guarded by Looper.class
final MessageQueue mQueue;    //管理的消息队列
final Thread mThread;    //所在的线程

private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

/**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. The main looper for your application
     * is created by the Android environment, so you should never need
     * to call this function yourself.  See also: {@link #prepare()}
     */
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

    /**
     * Returns the application's main looper, which lives in the main thread of the application.
     */
    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }

/** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
    public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

Looper类用来为一个线程开启一个消息循环。 默认情况下android中新创建的线程是没有开启消息循环的。(主线程除外,主线程系统会自动为其创建Looper对象,开启消息循环。)一个线程只能有一个Looper,对应一个MessageQueue。 Looper对象通过MessageQueue来存放消息和事件。

默认情况下Handler会与被定义时所在线程的Looper绑定,比如,Handler在主线程中定义,那么它是与主线程的Looper绑定。 mainHandler = new Handler() 等价于new Handler(Looper.myLooper()). Looper.myLooper():获取当前进程的looper对象。

looper类内部也包含一个空消息队列对象和空线程。Looper.prepare()调用Looper的构造函数。当创建Looper时,会自动创建一个消息队列,同时将内部线程对象指向创建Looper的线程,从而实现了绑定。当开启Looper后(looper.loop()),会自动进入无限for循环中,之后的流程就是
· Handler 给 MessageQueue 添加消息
· 然后 Looper 不断去遍历消息队列,如果没有消息则阻塞,有消息则回调handler的handlemessage方法进行处理。

在子线程中创建Handler:

class LooperThread extends Thread {
    public Handler mHandler;

      public void run() {
          Looper.prepare();

          mHandler = new Handler() {
              public void handleMessage(Message msg) {
                  // 这里处理消息
              }
          };

          Looper.loop();
      }

HandlerThread源码:

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }

    //也可以指定线程的优先级,注意使用的是 android.os.Process 而不是 java.lang.Thread 的优先级!
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }

    // 子类需要重写的方法,在这里做一些执行前的初始化工作
    protected void onLooperPrepared() {
    }

    //获取当前线程的 Looper
    //如果线程不是正常运行的就返回 null
    //如果线程启动后,Looper 还没创建,就 wait() 等待 创建 Looper 后 notify
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }

        synchronized (this) {
            while (isAlive() && mLooper == null) {    //循环等待
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }

    //调用 start() 后就会执行的 run()
    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();            //帮我们创建了 Looepr
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();    //Looper 已经创建,唤醒阻塞在获取 Looper 的线程
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();    
        Looper.loop();        //开始循环
        mTid = -1;
    }

    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }

    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }

    public int getThreadId() {
        return mTid;
    }
}

HandlerThread使用场景:
在子线程中执行耗时的、可能有多个任务的操作。
比如说多个网络请求操作,或者多文件 I/O 等。
使用 HandlerThread 的典型例子就是 IntentService

总结:HandlerThread是帮我们创建 Looper 的线程,让我们可以直接在线程中使用 Handler 来处理异步任务
HandlerThead
Message MessageQueue Handler Looper

相关文章

网友评论

      本文标题:Looper,handlerThread

      本文链接:https://www.haomeiwen.com/subject/kgbbnftx.html