Android之Handler和Loooper源码分析(1)

简介: Android之Handler和Loooper源码分析

1、handler在主线程和子线程互相通信(子线程和子线程的通信)简单使用

     我们使用handler,可以实现主线程和子线程之间的相互通信,然后子线程和子线程之间的通信,如果不清楚,基本用法请先参考我的这篇博客


Android之用Handler实现主线程和子线程互相通信以及子线程和子线程之间的通信  http://blog.csdn.net/u011068702/article/details/75577005



2、handler在主线程为什么不需要调用Looper.prepare()

我们看下Looper.java这个类,它在安卓android.os包下,我们看这个类的一开始的注释

  * <p>This is a typical example of the implementation of a Looper thread,
  * using the separation of {@link #prepare} and {@link #loop} to create an
  * initial Handler to communicate with the Looper.
  *
  * <pre>
  *  class LooperThread extends Thread {
  *      public Handler mHandler;
  *
  *      public void run() {
  *          Looper.prepare();
  *
  *          mHandler = new Handler() {
  *              public void handleMessage(Message msg) {
  *                  // process incoming messages here
  *              }
  *          };
  *
  *          Looper.loop();
  *      }
  *  }</pre>

很明显,在一个线程里面需要使用Handler之前需要Looper.prepare(),但是我们平时在主线程更新UI的时候,为什么没有看到这行代码呢?



我们看下ActivityThread.java这个类,它在安卓包名android.app目录下,我们知道ActivityThread.java这个类是安卓程序的入口,我们看下main函数的代码

    public static void main(String[] args) {
        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());
        Security.addProvider(new AndroidKeyStoreProvider());
        // 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"));
        }
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }


我们可以看到有Looper.prepareMainLooper()函数,我们点击进去

public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }


然后看到了prepare(false)函数,我们再点击这个函数


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));
    }

我们可以看到这里就调用prepare函数,所以主线程不需要调用Looper.prepare()函数,然后我们也可以看到这里有行这个代码




       if (sThreadLocal.get() != null) {

           throw new RuntimeException("Only one Looper may be created per thread");

       }


在Looper.java类中,我们的Looper保存在ThreadLocal里面




static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

用ThreadLocal修饰的变量,可以理解为只有当前线程可以改变这个参数,其它线程不可以改变这个参数,如果你对ThreadLocal不清楚,单独可以先看下我这篇博客的简单使用



java之ThreadLocal简单使用总结    http://blog.csdn.net/u011068702/article/details/75770226
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }

上面的代码写得很清楚了,如果当前的sThreadLocal对象里面有个Looper对象,那么就会抛出异常,而且英文也提示了,所以,一个线程为什么只能有一个Looper对象的原因,所以如果在程序里面,每个线程调用2次Looper.prepare()就会报错,我们再看这行代码




       sThreadLocal.set(new Looper(quitAllowed));


点击Looper的构造函数



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

里面构建了一个MessageQueue对象,上面我们分析一个线程只有一个Looper对象,那么Looper对象只构建一个,也就意味着MessageQueue对象也只构建一次,所以一个线程也只有一个MessageQueue对象的原因。



在main函数里面,也调用了Looper.loop()函数,后面分析这个方法



 


相关文章
|
3月前
|
安全 Android开发 开发者
【Android开发小技巧】扔掉这坑人的 Handler
【Android开发小技巧】扔掉这坑人的 Handler
40 0
|
8月前
|
Android开发
Android PackageManagerService源码分析和APK安装原理详解
Android PackageManagerService源码分析和APK安装原理详解
206 1
|
8月前
|
Android开发
Android面试常客之Handler全解1
Android面试常客之Handler全解
|
4月前
|
消息中间件 缓存 安全
android开发,使用kotlin学习消息机制Handler
android开发,使用kotlin学习消息机制Handler
84 0
|
8月前
|
XML 消息中间件 API
Android 中handler消息机制的理解
Android 中handler消息机制的理解
49 0
|
8月前
|
XML Android开发 数据格式
Android 中简单计时器的实现方法(Handler和TimerTask)
Android 中简单计时器的实现方法(Handler和TimerTask)
333 0
|
8月前
|
消息中间件 Android开发
Android面试常客之Handler全解2
Android面试常客之Handler全解
|
10月前
|
消息中间件 存储 安全
Android 13 Handler 源码
Handler 是一套 Android 消息传递机制。   在多线程应用场景中,将子线程中需要更新 UI 的操作消息,传递到 UI 主线程,从而实现子线程通知 UI 更新最终实现异步消息处理。说白了是用于线程之间的通信。 Handler主要有4个重要类:Handler、Message、MessageQueue、Looper。
|
11月前
|
Android开发
【Android篇】Handler通信机制(代码版)
通过点击按钮,让子线程1写字符串,传输到Message中,再在子线程1中用主线程的handle对象去发送消息,再让主线程判断是否为子线程1发过来的,再设置为Textview的文字。
60 0
|
XML Java Android开发
Android8.1 MTK平台 SystemUI源码分析之 网络信号栏显示刷新(下)
Android8.1 MTK平台 SystemUI源码分析之 网络信号栏显示刷新(下)
168 0