理解Android Hander、Looper、Message 、MessageQueue、HandlerThread

这几个类经常用到,以前理清后就再未管过,现在突然又迷糊了,现在又理清了,今天做个记录,以后不清楚了看看就清楚了。

有2篇文章写得非常好,我就不贴源码分析了,
 

Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系


http://blog.csdn.net/lmj623565791/article/details/38377229     点击打开链接

【从源码看Android】03Android MessageQueue消息循环处理机制(epoll实现)

http://blog.csdn.net/ashqal/article/details/32107099                点击打开链接


相信大家看完就非常清楚了,先大概讲下这几个类的原理使用。

Handler:用于线程间消息传递,handleMessage() 可以在主线程执行,也可以在子线程中执行,比如 经常用来子线程完事后通知主线程UI刷新;

Looper:一看名字就能猜到应该是用来做循环用的,调用 loop() 循环取消息队列中的消息,handler再回调 handleMessage() ;


Message:就是装消息的一个实体;

MessageQueue:处理消息实体对象的队列,是阻塞的;

他们怎么工作的呢?


首先创建一个Handler对象,重写handleMessage()方法,当线程完事后就调用handler对象sendMessage()方法,里面会把这个handler对象给message.target引用,然后Looper.loop()方法开启无限循环获取messageQueue中的message,当获取到一个message,message.target (即handler) 去调用dispatchMessage()方法,实际最终调用是handler.handleMessage(),好,到此也就一个循环了。

Looper中的loop()方法一直无限循环吗?

当消息队列没有消息了,那么Looper所在线程就等待了,当有新的消息来继续循环,直到调用quit()方法,才退出循环,不过我们平时多用于主线程和子线程通信,handler在主线程创建的、prepare()、loop()、quit()等方法没直接调用,不代表SDK的其他类不会默默的调用哦。


所以当Handler在子线程中创建的,就需要自己调用prepare()、loop()、quit()等方法了。
 

主线程中一启动APP就会在ActivityThread中调用一次loop(),所以不需要我们去调用

public final class ActivityThread {
  ...
   public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        SamplingProfilerIntegration.start();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        Process.setArgV0("<pre-initialized>");

        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
  ...
}

public final class Looper {
    ...
    /**
     * 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();
        }
    } 
  ...
}

第23行,Looper.prepareMainLooper();创建一个mianLooper,静态的,全局可用

第39行,Looper.loop();  当前线程(即主线程)开启无限处理消息循环

关闭APP会调用quit()

public final class ActivityThread {
  ...
  private class H extends Handler {   
    public void handleMessage(Message msg) {
       switch (msg.what) {
       ...
          case LAUNCH_ACTIVITY: 
	  if (mInitialApplication != null) {
               mInitialApplication.onTerminate();
          }
          Looper.myLooper().quit();
	  break;
       }
       ...
       Object obj = msg.obj;
       if (obj instanceof SomeArgs) {
          ((SomeArgs) obj).recycle();
       }
   }
  ...
}

注意点:prepare()一个线程只能调用一次,否则发生异常,每个线程中最多只有一个Looper、

Looper中只有一个MessageQueue对象;

public final class Looper {
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    ...
    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));
    }
    ...
}

public class Thread implements Runnable {
    ThreadLocal.ThreadLocalMap threadLocals = null;
    ...
}

不太了解TheadlLocal吗?可以看这篇博客

http://blog.csdn.net/msn465780/article/details/78673656      点击打开链接

sThreadLocal是一个静态成员变量,这里千万不要误解了,我之前误解为所有线程都共享,那么A线程12行set()

Looper实例后,如果B线程执行第9行,那不是不为null,就会抛异常了吗。

第18行,其实sThreadLocal并不是保存Looper实例的,而是Thread中成员变量ThreadLocal.ThreadLoalMap 

才是保存Looper实例的

第9行,sThreadLocal.get()是获取当前线程的ThreadLocal.ThreadLoalMap中的Looper实例,这里当前线程为key,

Looper实例为value

HandlerThread, 是官方封装的子线程,继承Thread,可以有Handler + Thread的作用,不过不是用来刷新UI的,因为HandlerThead相关的回调函数都是子线程的,你要刷新UI还得new个Handler去sendMessage(),那它存在的意义呢?


因为Handler + Thread中的Looper对象是在主线程工作的,一般情况消息不多没关系,一旦消息非常多,就是耗时的,可能就会引起UI卡顿,还有一些处理消息的操作并不需要在UI线程中,那么就可以使用HandlerThead,这样就分担了部分主线程的压力。

简单说下HandlerThead的原理把,其实就是一个普通的子线程,然后里面定义了一个Looper,然后用Looper.loop()循环传递消息,因为Looper在哪个线程那么它工作就在哪个线程里面,HandlerThead是子线程,那么它创建的Looper肯定在子线程了,Handler一般情况都创建在主线程用于刷新UI,所以它里面传递消息的Looper也是在主线程的,详细代码分析就不贴了,这个类就100多行代码,相信大家都能看懂,这里还是写下关键代码的分析如下:

public class HandlerThread extends Thread {
    ...
    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

    /**
     * This method returns the Looper associated with this thread. If this thread not been started
     * or for any reason isAlive() returns false, this method will return null. If this thread
     * has been started, this method will block until the looper has been initialized.  
     * @return The looper.
     */
    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }
        
        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
  ...
}

当创建HandlerThead调用start()方法那么就会开始执行这个run(),同时HandlerThead调用getLooper()传递给Handler,他们几乎是一起开始调用的,不过的会发现里面都有synchronized 关键,这个目的很简单,就是说获取Looper的时候可能Looper还未创建出来,那么就需要同步上锁,getLooper()就停在wait()这,当run()方法创建好Looper了,就用上锁的这个对象调用notifyAll,getLooper就从刚才暂停的地方继续执行,最终返回Looper给Handler。
这里注意:两个方法中synchronized 字段上锁的对象必须同一个,notifyALL、wait方法必须是这个上锁的对象调用,源码中用的this,也是将就原则,反正this都有直接用,当然用其他任何对象都可以。


好了相信基本应该清楚了,又可以愉快玩耍了偷笑

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值