先来一段Looper类头部的解释说明:
/**
* 这是用于运行线程的消息循环的类。默认的线程没有与它们关联的消息循环;
* 在运行循环的线程中,调动prepare方法可以创建一个Looper对象, 然后调动loop方法,循环处理它的
* 消息队列中的消息,知道循环退出为止。
* 与消息循环相关的大多数交互是通过Handler类处理的。
* 下面是一个Looper线程上线的经典例子,
* 使用prepare和loop两个方法来初始化一个含有Looper的线程,简称Looper线程。
*
*
* 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();
* }
* }
*/
Activity部分源码:
public class Activity extends ContextThemeWrapper
implements LayoutInflater.Factory2,
Window.Callback, KeyEvent.Callback,
OnCreateContextMenuListener, ComponentCallbacks2,
Window.OnWindowDismissedCallback {
ActivityThread mMainThread;
// we must have a handler before the FragmentController is constructed
final Handler mHandler = new Handler();
//...
}
public final class ActivityThread {
final Looper mLooper = Looper.myLooper();
public static void main(String[] args) {
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");
}
}
/**
* 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();
}
}
Looper.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));
}
/** 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);
}
//这是个最终类,不能被继承
public final class Looper {
//sThreadLocal.get()方法会返回null,除非你调用了prepare()方法。
static final ThreadLocal sThreadLocal = new ThreadLocal();
private static Looper sMainLooper; // guarded by Looper.class
//这就是传说中的消息队列,有Looper自己管理
final MessageQueue mQueue;
final Thread mThread;
/** 初始化当前线程的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);
}
//每个线程只能创建一个looper对象
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,标记其为应用程序的main looper。
* 应用程序的主looper是由Android环境的创建, 所以你没有必要自己主动的调用此方法。
* 请查看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();
}
}
/**
* 获取application UIThread的looper,加了线程类锁
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
/**
* 在当前线程中运行消息队列循环,直到调用quit()方法结束循环。
*/
public static void loop() {
final Looper me = myLooper();//获取当前线程自己的looper
if (me == null) {//如果looper为null,可能是prepare()方法没有调用
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// 确保这个线程的身份是本地进程
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
//死循环,消息调度
for (;;) {
Message msg = queue.next(); // 此方法可能会阻塞
if (msg == null) {
// 如果没有消息关联到这个消息队列中时就退出
return;
}
//此处是让message去找自己的宿主,后期
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
/**
* 返回当前线程的looper对象,如果当前线程还没有关联上looper,可能会返回null。
* 例如,当前线程还没有执行到Looper.prepare()方法时,你就调用了myLooper()方法。
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
/**
* 返回与当前线程关联的MessageQueue对象。
* 调用此方法前必须确保当前线程已经运行了一个looper,
* 否则必定NullPointerException登门拜访
*/
public static @NonNull MessageQueue myQueue() {
return myLooper().mQueue;
}
//在构造Looper的时候,内部构造了一个MessageQueue对象
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
/**
* 如果当前线程是looper线程,则返回true,否则返回false.
*/
public boolean isCurrentThread() {
return Thread.currentThread() == mThread;
}
/**
* Control logging of messages as they are processed by this Looper. If
* enabled, a log message will be written to printer
* at the beginning and ending of each message dispatch, identifying the
* target Handler and message contents.
*
* @param printer A Printer object that will receive log messages, or
* null to disable message logging.
*/
public void setMessageLogging(@Nullable Printer printer) {
mLogging = printer;
}
/**
* 退出looper循环.
*
* Causes the {@link #loop} method to terminate without processing any
* more messages in the message queue.
*
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
*
* Using this method may be unsafe because some messages may not be delivered
* before the looper terminates. Consider using {@link #quitSafely} instead to ensure
* that all pending work is completed in an orderly manner.
*
*
* @see #quitSafely
*/
public void quit() {
mQueue.quit(false);
}
/**
* 安全的退出消息循环
*
* Causes the {@link #loop} method to terminate as soon as all remaining messages
* in the message queue that are already due to be delivered have been handled.
* However pending delayed messages with due times in the future will not be
* delivered before the loop terminates.
*
* Any attempt to post messages to the queue after the looper is asked to quit will fail.
* For example, the {@link Handler#sendMessage(Message)} method will return false.
*
*/
public void quitSafely() {
mQueue.quit(true);
}
/**
* 返回与当前线程关联的looper
*
* @return The looper's thread.
*/
public @NonNull Thread getThread() {
return mThread;
}
/**
* 返回当前线程的looper的MessageQueue
*
* @return The looper's message queue.
*/
public @NonNull MessageQueue getQueue() {
return mQueue;
}
/**
* Dumps the state of the looper for debugging purposes.
*
* @param pw A printer to receive the contents of the dump.
* @param prefix A prefix to prepend to each line which is printed.
*/
public void dump(@NonNull Printer pw, @NonNull String prefix) {
pw.println(prefix + toString());
mQueue.dump(pw, prefix + " ");
}
@Override
public String toString() {
return "Looper (" + mThread.getName() + ", tid " + mThread.getId()
+ ") {" + Integer.toHexString(System.identityHashCode(this)) + "}";
}
}
MainActivity代码:
public class MainActivity extends Activity implements OnClickListener {
private Button uiBtn, looperBtn, quitBtn;
private TextView show;
private MyLooperThread looperThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
uiBtn = (Button) findViewById(R.id.uiBtn);
looperBtn = (Button) findViewById(R.id.looperBtn);
quitBtn = (Button) findViewById(R.id.quitBtn);
show = (TextView) findViewById(R.id.show);
uiBtn.setOnClickListener(this);
looperBtn.setOnClickListener(this);
quitBtn.setOnClickListener(this);
// 创建和启动looper线程
looperThread = new MyLooperThread(this,show);
looperThread.start();
}
@Override
public void onClick(View v) {
Button btn = (Button) v;
switch (v.getId()) {
case R.id.uiBtn:
// 在ui中自己修改textview
show.setText(btn.getText());
break;
case R.id.quitBtn:
// 终止looper线程
looperThread.getLooper().quit();
break;
case R.id.looperBtn:
// 获取looper中的handler,发送消息让handler处理,更新ui
looperThread.getHandler().obtainMessage(200, btn.getText()).sendToTarget();
break;
default:
break;
}
}
}
/**
* 用来处理looper循环的线程 用于测试,在looper线程中看能否修改ui
*
* @author duke
*/
public class MyLooperThread extends Thread {
private static final String TAG = MyLooperThread.class.getSimpleName();
// 子线程的looper
private Looper myLooper;
// 子线程的handler
private Handler mHandler;
// 用于测试的textview
private TextView testView;
private Activity activity;
public Looper getLooper() {
return myLooper;
}
public Handler getHandler() {
return mHandler;
}
public MyLooperThread(Context context, TextView view) {
this.activity = (Activity) context;
testView = view;
}
@Override
public void run() {
super.run();
// 调用了此方法后,当前线程拥有了一个looper对象
Looper.prepare();
Log.v(TAG, "消息循环开始");
if (myLooper == null) {
while (myLooper == null) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 调用此方法获取当前线程的looper对象
myLooper = Looper.myLooper();
}
}
// 当前handler与当前线程的looper关联
mHandler = new Handler(myLooper) {
@Override
public void handleMessage(Message msg) {
Log.v(TAG, "处理消息:" + msg.obj);
//this thread's TextView
addTextViewInChildThread().setText(String.valueOf(msg.obj));
//main thread's TextView
//testView.setText(String.valueOf(msg.obj));
}
};
Looper.loop();
Log.v(TAG, "looper消息循环结束,线程终止");
}
/**
* 创建TextView
* http://blog.csdn.net/imyfriend/article/details/6877959
* @return
*/
private TextView addTextViewInChildThread() {
TextView textView = new TextView(activity);
//ViewGroup.LayoutParams txparams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
//textView.setLayoutParams(txparams);
textView.setBackgroundColor(Color.GRAY);
textView.setGravity(Gravity.CENTER);
textView.setTextSize(20);
WindowManager windowManager = activity.getWindowManager();
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,//width of textView
WindowManager.LayoutParams.WRAP_CONTENT,//height of textView
0, 0,//x,y of textView in screen
WindowManager.LayoutParams.FIRST_SUB_WINDOW,
WindowManager.LayoutParams.TYPE_TOAST,
PixelFormat.TRANSPARENT);
windowManager.addView(textView, params);
return textView;
}
}