Android 主线程之旅——PSVM(public static void main)


本文翻译自Square官方技术博客
当碰到与Android主线程交互相关的Bug时,我决定好好去看看Android的主线程究竟是怎么一回事。这篇文章就是描述我的Android主线程之旅的第一部分。

PSVM

public class BigBang {
  public static void main(String... args) {
    // The Java universe starts here.
  }
}

众所周知,所有的Java程序的入口都是 public static void main() 方法。这对所有的Java 桌面程序、J2EE以及Android程序都是成立的。
当Android启动时,它会开启一个叫做 ZygoteInit 的Linux进程。这个进程是一个Dalvik 虚拟机,它会在一个线程上面加载Android SDK里面大部分的常用类,然后等待。
当Android启动一个新的Android程序时,Android系统会 fork 这个 ZygoteInit 进程。接着子进程里面的线程会停止等待,然后调用ActivityThread.main()方法。
1411804069283-zygote
Wikipedia上面的一个Zygote。根据Wikipedia的定义,一个 Zygote 就是一个受精卵细胞。

Loopers

在继续深入之前,我们需要来看一看Looper这个类。
使用looper可以连续地为一个线程处理它的消息。
每一个looper都有一个消息队列(一个 MessageQueue)。
每一个looper都有一个处理消息队列里面所有消息的loop()方法,这个方法会在消息队列为空时阻塞。
Looper.loop() 方法里面的代码类似这样:

void loop() {
  while(true) {
    Message message = queue.next(); // 消息队列为空时阻塞
    dispatchMessage(message);
    message.recycle();
  }
}

每一个looper都会和一个线程绑定。要创建一个新的looper并将它同当前的线程绑定起来,你必须要调用Looper.prepare()方法。这些looper都被存储在Looper 类里面的静态ThreadLocal变量里面。你可以通过调用Looper.myLooper()方法来获取与当前线程相关联的Looper。
当然实际情况不要这么复杂,其实HandlerThread类已经帮你做了所有事情:

HandlerThread thread = new HandlerThread("SquareHandlerThread");
thread.start(); // starts the thread.
Looper looper = thread.getLooper();

HandlerThread的内部代码类似于这样:

class HandlerThread extends Thread {
  Looper looper;
  public void run() {
    Looper.prepare(); // 创建一个Looper对象并将它保存到一个ThreadLocal 对象里面。
    looper = Looper.myLooper(); // 从ThreadLocal 里面获取Looper以便后来的使用。
    Looper.loop(); // Loop forever.
  }
}

 

Handlers

handler 天生就是 looper 的好伙伴。
一个 handler 有两个作用:

  • 从任意线程发送消息给一个looper的消息队列;
  • 处理相关联的looper发过来的消息。
// Each handler is associated to one looper.
Handler handler = new Handler(looper) {
  public void handleMessage(Message message) {
    // 处理给定looper相关联的线程上面的消息
    if (message.what == DO_SOMETHING) {
      // do something
    }
  }
};
//创建一个与这个handler相关联的message
Message message = handler.obtainMessage(DO_SOMETHING);
// 将message 添加到looper 的消息队列queue.
// 这个方法能在任意线程上调用
handler.sendMessage(message);

你可以为一个looper关联多个handler。looper会把message发送到message.target(它就是一个handler)这里。
一个常用简单的用法就是使用handler来发送一个Runnable对象:

//创建包含一个runnable引用的message,然后将这个message添加到这个looper的消息队列
handler.post(new Runnable() {
  public void run() {
    // 这会在与handler相关联的looper对应的线程上运行
  }
});

一个handler也可以在没有设置looper的情况下被创建。:

// 千万不要这样做
Handler handler = new Handler();

handler的无参构造函数会调用方法来获取与当前线程相关联的looper。这个时候你要注意,可能当前线程不是你的handler想关联的线程。
大部分时间,你只需要创建一个在主线程上面发送消息的handler就行了:

Handler handler = new Handler(Looper.getMainLooper());

Back to PSVM

让我们再来看看 ActivityThread.main()这个方法。下面就是这个方法的一些内部实现:

public class ActivityThread {
  public static void main(String... args) {
    Looper.prepare();
    // 你可以在任意时刻调用Looper.getMainLooper()方法来获取主线程的looper
    Looper.setMainLooper(Looper.myLooper());
    // 发送第一波消息给主线程的 looper.
    // { ... }
    Looper.loop();
  }
}

现在你知道为什么这个线程被称为主线程了吧:) .
注意: 主线程最先做的几件事情之一就是创建Application对象,然后调用Application.onCreate()方法。
在下一篇文章中,我们将会分析Android生命周期和主线程之间的关系以及bug是怎么出现的。


《“Android 主线程之旅——PSVM(public static void main)”》 有 2 条评论

  1. 既然主線程的Looper.loop()在沒有消息的時候會阻塞,那主線程不就沒法做其他操作了?

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注