【从源码看Android】01从Looper说起

1 为什么以这一个点为开头?

因为面试的时候被问到ThreadLocal完全不懂,前几天发现Looper内正好使用了ThreadLocal,那么从哪里跌倒就从哪里爬起来。

2 什么是Looper

首先看/sdk/docs/reference/android/os/Looper.html内的定义

Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.

Looper类用于在一个线程中运行一个消息循环。默认的线程不包含消息循环。

如果需要创建一个Looper,在Thread的run函数中调用Looper.prepare()

接着调用Thread.loop()函数,直到消息队列停止。

简单的说,Looper就是一个消息循环,在一个线程中不停的去消息队列里poll新消息出来给Handler处理,

3 如何创建Looper

import android.os.Handler;import android.os.Looper;import android.os.Message;import android.support.v7.app.ActionBarActivity;import android.os.Bundle;import android.util.Log;public class MainActivity extends ActionBarActivity {private static final String TAG = "MainActivity";private class LooperThread extends Thread{public Handler mHandler;@Overridepublic void run() {Looper.prepare();mHandler = new Handler() {@Overridepublic void handleMessage(Message msg){Log.i(TAG,msg.toString());}};Looper.loop();}}private LooperThread mLooperThread = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mLooperThread = new LooperThread();mLooperThread.start();}}这是reference中给出的子线程中Looper的构建方法

a 创建新线程,重写run函数

b 调用Looper.prepare()

c 创建Handler

d 调用Looper.loop()

我们下面分4部分解读源代码

3.1 Looper概览

– 成员变量

public final class Looper {private static final String TAG = "Looper";// sThreadLocal.get() will return null unless you’ve called prepare().static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();private static Looper sMainLooper; // guarded by Looper.classfinal MessageQueue mQueue;final Thread mThread;private Printer mLogging;}

Looper拥有6个成员变量,其中mLogging和Tag先忽略

sMainLooper、ThreadLocal为static成员

mQueue、mThread为实例的成员变量

– 成员函数

Public Methods

void(Printerpw,Stringprefix)

staticLooper()

Returns the application’s main looper, which lives in the main thread of the application.

Thread()

Return the Thread associated with this Looper.

static void()

Run the message queue in this thread.

staticLooper()

Return the Looper object associated with the current thread.

staticMessageQueue()

Return theMessageQueueobject associated with the current thread.

static void()

Initialize the current thread as a looper.

static void()

Initialize the current thread as a looper, marking it as an application’s main looper.

void()

Quits the looper.

void()

Quits the looper safely.

void(Printerprinter)

Control logging of messages as they are processed by this Looper.

String()

Returns a string containing a concise, human-readable description of this object.

3.2 调用Looper.prepare()

我们先看看Looper.prepare()定义

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));}从静态的prepare函数可以每一个Thread只能对应一个Looper,不然会报RuntimeException

而prepare函数所做的事情只是在全局的sThreadLocal中存放了个新的Looper

private Looper(boolean quitAllowed) {mQueue = new MessageQueue(quitAllowed);mThread = Thread.currentThread();}new Looper时赋值了mQueue和mThread

既然sThreadLocal是个全局的静态变量,那么所有的Looper类都共享同一个sThreadLocal

sThreadLocal.set操作定义如下

java.lang.ThreadLocal.java

public void set(T value) {Thread currentThread = Thread.currentThread();Values values = values(currentThread);if (values == null) {values = initializeValues(currentThread);}values.put(this, value);}即从当前调用线程中取出values对象,然后往这个values对象存放这个Looper

需要注意的是每个Thread中都有一个values对象,

这个values对象再按照ThreadLocal<Looper>sThreadLocal对象在当前线程的values哈希表中找出对应的Looper

那么这个Looper就对应为当前线程的Looper

那么使用ThreadLocal有什么好处呢?

好处是显而易见的,如果用全局的HashMap管理一个Thread对应一个Looper,

那么增删改某个Looper对象时就需要进行同步操作,这大大增加了系统开销

环境不会改变,解决之道在于改变自己。

【从源码看Android】01从Looper说起

相关文章:

你感兴趣的文章:

标签云: