本文目標(biāo)归斤,采用簡單易懂的方式理解Android中的Handler機制枝冀,以及自己動手去模擬實現(xiàn)Android系統(tǒng)的Handler機制舞丛;
Handler 是為了解決Android中子線程與主線程之間通信的相關(guān)問題而存在的,主要涉及到:Handler果漾、Message球切、MessageQueue、Looper這幾個系統(tǒng)類绒障,它們存放在
android.os
包下吨凑;
簡單介紹下它們的作用:
- Handler :子線程向主線程發(fā)送消息、主線程處理接收到的消息户辱;
- Message:消息載體鸵钝,如果傳輸數(shù)據(jù)簡單可以直接使用arg1、arg2這兩個整型數(shù)據(jù)庐镐,如果需要傳復(fù)雜的消息恩商,使用obj傳輸對象數(shù)據(jù);
- MessageQueue:消息隊列必逆,用來存儲管理當(dāng)前的線程中的所有Message消息怠堪;
- Looper :消息輪詢器,不斷的從消息隊列MessageQueue中取出Message進行分發(fā)名眉;
一粟矿、基本使用方式
講解之前我們先看下使用案例,如下:
功能描述:點擊按鈕開始倒計時损拢,將當(dāng)前剩余的時間更新到UI控件TextView中陌粹;
public class HandlerActivity extends AppCompatActivity {
private static final int UPDATE = 0x1;
public Button btnStartCountDown;
public TextView tvCountDown;
//默認(rèn)是在主線程中執(zhí)行
private final MyHandler mHandler = new MyHandler(this);
//繼承實現(xiàn)自己的Handler,處理子線程與主線程的通訊交互
static class MyHandler extends Handler {
//使用弱引用福压,防止內(nèi)存泄露
private final WeakReference<HandlerActivity> mActivity;
private MyHandler(HandlerActivity mActivity) {
this.mActivity = new WeakReference<>(mActivity);
}
//重寫handleMessage進行處理接收到的Message
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//獲取引用的UI主線程Activity申屹,用來獲取UI線程的控件等
HandlerActivity activity = mActivity.get();
if (activity != null) {
//分發(fā)處理消息
switch (msg.what) {
case UPDATE:
activity.tvCountDown.setText("還有" + String.valueOf(msg.arg1) + "秒");
break;
}
}
}
}
//模擬子線程進行耗時任務(wù)
private final Runnable mRunnable = new Runnable() {
@Override
public void run() {
//這里做的是一個倒計時定時一秒發(fā)送一次數(shù)據(jù)
for (int i = 60; i > 0; i--) {
//構(gòu)建屬于子線程的Message
Message msg = new Message();
msg.what = UPDATE;
msg.arg1 = i;
//通過主線程中的Handler實例進行消息發(fā)送绘证,將子線程中的消息發(fā)送到主線程中
mHandler.sendMessage(msg);
try {
//休眠1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//打印Log
Log.i("TAG", "還有 " + i + " 秒");
}
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
btnStartCountDown = findViewById(R.id.btn_start_count_down);
tvCountDown = findViewById(R.id.tv_count_down);
btnStartCountDown.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//開啟子線程運行耗時操作
new Thread(mRunnable).start();
}
});
}
}
可以看出Handler的使用很簡單,但是他卻可以幫助我們有效的解決子線程與主線程間通信的問題哗讥,接下來講解下原理;
二胞枕、源碼分析
對照上面的流程圖杆煞,我們進行源碼片段分析,關(guān)鍵的幾個地方提取出來腐泻,如下:
public final class Looper {
// 線程本地存儲,通過它就可以在指定的線程中存儲數(shù)據(jù)决乎,然后只有在這個指定的線程中才能夠訪問得到之前存儲的數(shù)據(jù)。
// 但是對于其他線程來說派桩,是獲取不到保存在另外線程中的數(shù)據(jù)的构诚。
// 一般來說,當(dāng)某些數(shù)據(jù)是以線程為作用域并且不同的線程對應(yīng)著不同的數(shù)據(jù)副本的時候铆惑,就可以考慮使用ThreadLocal了
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
//消息隊列
final MessageQueue mQueue;
private Looper() {
//初始化消息隊列
mQueue = new MessageQueue();
}
/**
* 在當(dāng)前的線程中準(zhǔn)備一個消息輪詢器
*/
public static void prepare() {
//一個線程只能對應(yīng)一個輪詢器
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//向ThreadLocal添加一個輪詢器
sThreadLocal.set(new Looper());
}
/**
* 返回當(dāng)前線程對應(yīng)的輪詢器
*
* @return Looper
*/
public static Looper myLooper() {
return sThreadLocal.get();
}
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
//取出當(dāng)前的線程的Looper對象
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//取出Looper對應(yīng)的MessageUeue
final MessageQueue queue = me.mQueue;
//……
for (;;) {
//取出MessageQueue中的棧頂?shù)南? Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//……
try {
// 調(diào)用Message對應(yīng)的Handler中的dispatchMessage(Message msg)進行消息的分發(fā)處理
msg.target.dispatchMessage(msg);
//……
} finally {
//……
}
//釋放資源
msg.recycleUnchecked();
}
}
}
public class Handler {
//持有當(dāng)前線程的Looper
final Looper mLooper;
//持有Looper中的MessageQueue消息隊列范嘱,sendMessage需要向隊列插入消息
final MessageQueue mQueue;
public Handler() {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
}
/**
* 子類需要重寫這個方法寫入自己的處理邏輯
*
* @param msg Message消息
*/
public void handleMessage(Message msg) {
}
/**
* 調(diào)度消息
*
* @param msg Message消息
*/
public void dispatchMessage(Message msg) {
//這里為了簡單說明原理與原碼有些不一樣,刪減了一些判斷邏輯
if (msg.callback != null) {
handleCallback(msg);
} else {
handleMessage(msg);
}
}
/**
* 處理回調(diào)
*
* @param message Message消息
*/
private static void handleCallback(Message message) {
//取出Message中 Runnable 進行運行
message.callback.run();
}
/**
* 發(fā)送一條Message消息
*
* @param msg 要發(fā)送的Message消息
* @return 是否發(fā)送成功
*/
public final boolean sendMessage(Message msg) {
return sendMessageDelayed(msg, 0);
}
/**
* 發(fā)送延遲消息
*
* @param msg 要發(fā)送的Message消息
* @param delayMillis 要延遲的時間
* @return 是否發(fā)送成功
*/
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
//這里很巧妙的將消息的時間點進行延長员魏,從而達(dá)到了延遲發(fā)送的效果
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
/**
* 發(fā)送消息所對應(yīng)的時間
*
* @param msg 要發(fā)送的Message消息
* @param uptimeMillis 對應(yīng)的消息所在的時間點
* @return
*/
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//獲取當(dāng)前線程對應(yīng)的Looper中的MessageQueue
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
//消息壓入隊列操作
return enqueueMessage(queue, msg, uptimeMillis);
}
/**
* 消息壓入消息隊列操作
*
* @param queue 當(dāng)前Handler對應(yīng)的消息隊列
* @param msg 要發(fā)送的Message消息
* @param uptimeMillis 壓入隊列的時間丑蛤,系統(tǒng)的實習(xí)會對這個時間進行排序,從而保證消息的有序出棧 {@link MessageQueue#next()}
* @return 是否壓入隊列成功
*/
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
return queue.enqueueMessage(msg, uptimeMillis);
}
}
public class Message implements Parcelable {
//用戶定義的消息代碼撕阎,以便收件人可以識別此消息的內(nèi)容
public int what;
//如果只是傳遞整形數(shù)據(jù)可以使用 arg1受裹、arg2
public int arg1;
public int arg2;
//如果傳遞復(fù)雜數(shù)據(jù)可以使用這個
public Object obj;
//標(biāo)記當(dāng)前的Message要作用在那個Handler中
Handler target;
//當(dāng)前的Message要執(zhí)行的子線程
Runnable callback;
// sometimes we store linked lists of these things
Message next;
private static final Object sPoolSync = new Object();
private static Message sPool;
public Message() {
}
/**
* 這里是性能優(yōu)化,從線程池獲取一個對象虏束,避免重新創(chuàng)建對象棉饶,本案例中沒有使用到這個特性
*
* @return Message
*/
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
return m;
}
}
return new Message();
}
//////////////////////////////////////下面是實現(xiàn)Parcelable固定的寫法與邏輯關(guān)系不大/////////////////////////////////////////////
public static final Parcelable.Creator<Message> CREATOR
= new Parcelable.Creator<Message>() {
public Message createFromParcel(Parcel source) {
Message msg = Message.obtain();
msg.readFromParcel(source);
return msg;
}
public Message[] newArray(int size) {
return new Message[size];
}
};
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
if (callback != null) {
throw new RuntimeException(
"Can't marshal callbacks across processes.");
}
dest.writeInt(what);
dest.writeInt(arg1);
dest.writeInt(arg2);
if (obj != null) {
try {
Parcelable p = (Parcelable) obj;
dest.writeInt(1);
dest.writeParcelable(p, flags);
} catch (ClassCastException e) {
throw new RuntimeException(
"Can't marshal non-Parcelable objects across processes.");
}
} else {
dest.writeInt(0);
}
}
private void readFromParcel(Parcel source) {
what = source.readInt();
arg1 = source.readInt();
arg2 = source.readInt();
if (source.readInt() != 0) {
obj = source.readParcelable(getClass().getClassLoader());
}
}
}
public final class MessageQueue {
//獲取消息隊列的下一個數(shù)據(jù)
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) {
dispose();
return null;
}
// If first time idle, then get the number of idlers to run.
// Idle handles only run if the queue is empty or if the first message
// in the queue (possibly a barrier) is due to be handled in the future.
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
//向隊列中添加一個消息
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
//這里調(diào)用的jni進行了Message存儲
nativeWake(mPtr);
}
}
return true;
}
}
三、自定義實現(xiàn)Handler機制
通過上面的源碼分析我們不難看出Handler镇匀、Message照藻、MessageQueue、Looper之間的關(guān)系坑律,畫一個類圖解釋一下岩梳,可以看到下圖中所描述的,這四個類相互持有晃择,并且是一一對應(yīng)的關(guān)系冀值;
經(jīng)過上面的一系列分析我們來自己手動實現(xiàn)Handler機制。
public class Looper {
//靜態(tài)常量宫屠,整個APP共享這一個
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<>();
//跟當(dāng)前的線程持有的Looper綁定的消息隊列
final MessageQueue mQueue;
private Looper() {
//初始化消息隊列
mQueue = new MessageQueue();
}
/**
* 在當(dāng)前的線程中準(zhǔn)備一個消息輪詢器
*/
public static void prepare() {
//一個線程只能對應(yīng)一個輪詢器
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//向ThreadLocal添加一個輪詢器
sThreadLocal.set(new Looper());
}
/**
* 返回當(dāng)前線程對應(yīng)的輪詢器
*
* @return Looper
*/
public static Looper myLooper() {
return sThreadLocal.get();
}
/**
* 開啟輪詢
*/
public static void loop() {
//獲取當(dāng)前線程的輪詢器
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//獲取輪詢器對應(yīng)的消息隊列
final MessageQueue queue = me.mQueue;
//永真循環(huán)不斷地去取消息隊列中的消息
for (; ; ) {
//取出消息隊列中Message消息
Message msg = queue.next(); // might block
// 由于我們這里采用的是java幫我們實現(xiàn)的BlockingQueue列疗,
// 這里跟系統(tǒng)的實現(xiàn)判斷有些不一樣
if (msg != null) {
//將取出消息給發(fā)出當(dāng)前消息的Handler的dispatchMessage進行消息的調(diào)度
msg.target.dispatchMessage(msg);
}
}
}
}
public class Handler {
//持有當(dāng)前線程的Looper
final Looper mLooper;
//持有Looper中的MessageQueue消息隊列,sendMessage需要向隊列插入消息
final MessageQueue mQueue;
public Handler() {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
}
/**
* 子類需要重寫這個方法寫入自己的處理邏輯
*
* @param msg Message消息
*/
public void handleMessage(Message msg) {
}
/**
* 調(diào)度消息
*
* @param msg Message消息
*/
public void dispatchMessage(Message msg) {
//這里為了簡單說明原理與原碼有些不一樣浪蹂,刪減了一些判斷邏輯
if (msg.callback != null) {
handleCallback(msg);
} else {
handleMessage(msg);
}
}
/**
* 處理回調(diào)
*
* @param message Message消息
*/
private static void handleCallback(Message message) {
//取出Message中 Runnable 進行運行
message.callback.run();
}
/**
* 發(fā)送一條Message消息
*
* @param msg 要發(fā)送的Message消息
* @return 是否發(fā)送成功
*/
public final boolean sendMessage(Message msg) {
return sendMessageDelayed(msg, 0);
}
/**
* 發(fā)送延遲消息
*
* @param msg 要發(fā)送的Message消息
* @param delayMillis 要延遲的時間
* @return 是否發(fā)送成功
*/
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
//這里很巧妙的將消息的時間點進行延長抵栈,從而達(dá)到了延遲發(fā)送的效果
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
/**
* 發(fā)送消息所對應(yīng)的時間
*
* @param msg 要發(fā)送的Message消息
* @param uptimeMillis 對應(yīng)的消息所在的時間點
* @return
*/
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//獲取當(dāng)前線程對應(yīng)的Looper中的MessageQueue
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
//消息壓入隊列操作
return enqueueMessage(queue, msg, uptimeMillis);
}
/**
* 消息壓入消息隊列操作
*
* @param queue 當(dāng)前Handler對應(yīng)的消息隊列
* @param msg 要發(fā)送的Message消息
* @param uptimeMillis 壓入隊列的時間告材,系統(tǒng)的實習(xí)會對這個時間進行排序,從而保證消息的有序出棧 {@link MessageQueue#next()}
* @return 是否壓入隊列成功
*/
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
return queue.enqueueMessage(msg, uptimeMillis);
}
}
public class Message implements Parcelable {
//用戶定義的消息代碼古劲,以便收件人可以識別此消息的內(nèi)容
public int what;
//如果只是傳遞整形數(shù)據(jù)可以使用 arg1斥赋、arg2
public int arg1;
public int arg2;
//如果傳遞復(fù)雜數(shù)據(jù)可以使用這個
public Object obj;
//標(biāo)記當(dāng)前的Message要作用在那個Handler中
Handler target;
//當(dāng)前的Message要執(zhí)行的子線程
Runnable callback;
// sometimes we store linked lists of these things
Message next;
private static final Object sPoolSync = new Object();
private static Message sPool;
public Message() {
}
/**
* 這里是性能優(yōu)化,從線程池獲取一個對象产艾,避免重新創(chuàng)建對象疤剑,本案例中沒有使用到這個特性
*
* @return Message
*/
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
return m;
}
}
return new Message();
}
//////////////////////////////////////下面是實現(xiàn)Parcelable固定的寫法與邏輯關(guān)系不大/////////////////////////////////////////////
public static final Parcelable.Creator<Message> CREATOR
= new Parcelable.Creator<Message>() {
public Message createFromParcel(Parcel source) {
Message msg = Message.obtain();
msg.readFromParcel(source);
return msg;
}
public Message[] newArray(int size) {
return new Message[size];
}
};
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
if (callback != null) {
throw new RuntimeException(
"Can't marshal callbacks across processes.");
}
dest.writeInt(what);
dest.writeInt(arg1);
dest.writeInt(arg2);
if (obj != null) {
try {
Parcelable p = (Parcelable) obj;
dest.writeInt(1);
dest.writeParcelable(p, flags);
} catch (ClassCastException e) {
throw new RuntimeException(
"Can't marshal non-Parcelable objects across processes.");
}
} else {
dest.writeInt(0);
}
}
private void readFromParcel(Parcel source) {
what = source.readInt();
arg1 = source.readInt();
arg2 = source.readInt();
if (source.readInt() != 0) {
obj = source.readParcelable(getClass().getClassLoader());
}
}
}
public class MessageQueue {
private static final int MAX_QUEUE_SIZE = 50;
// 這里使用BlockingQueue集合進行模擬Native層的隊列
// 后續(xù)在進行講解Android中的C++如何實現(xiàn)的Message隊列操作
final BlockingQueue<Message> mMessages;
MessageQueue() {
//創(chuàng)建固定大小的消息隊列
mMessages = new ArrayBlockingQueue<>(MAX_QUEUE_SIZE);
}
/**
* 取出隊列中的下一個消息
*
* @return Message消息
*/
Message next() {
Message msg = null;
try {
//從隊列中取出頭部的消息,并從隊列中移除闷堡,通知 {@link BlockingQueue#put()} 可以入棧
msg = mMessages.take();
} catch (InterruptedException e) {
e.printStackTrace();
}
//將取出的消息返回
return msg;
}
/**
* 消息壓入隊列操作
*
* @param msg 要操作的消息
* @param when 壓入的時間
* @return 是否要入成功
*/
boolean enqueueMessage(Message msg, long when) {
try {
//壓入消息隊列隘膘,如果消息隊列處于飽和狀態(tài),這里則會出現(xiàn) block,直到 有調(diào)用 {@link BlockingQueue#take()}
mMessages.put(msg);
return true;
} catch (InterruptedException e) {
e.printStackTrace();
}
return false;
}
}
改寫一下測試代碼杠览,測試我們自己定義的Handler機制是否能夠?qū)崿F(xiàn)子線程與主線程的通信
public class CustomerHandlerActivity extends AppCompatActivity {
private static final int UPDATE = 0x1;
//默認(rèn)是在主線程中執(zhí)行
private MyHandler mHandler = null;
//繼承實現(xiàn)自己的Handler弯菊,處理子線程與主線程的通訊交互
static class MyHandler extends Handler {
//使用弱引用,防止內(nèi)存泄露
private final WeakReference<CustomerHandlerActivity> mActivity;
private MyHandler(CustomerHandlerActivity mActivity) {
this.mActivity = new WeakReference<>(mActivity);
}
//重寫handleMessage進行處理接收到的Message
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//獲取引用的UI主線程Activity踱阿,用來獲取UI線程的控件等
CustomerHandlerActivity activity = mActivity.get();
if (activity != null) {
//分發(fā)處理消息
switch (msg.what) {
case UPDATE:
//打印Log
Log.i("TAG", "還有 " + String.valueOf(msg.arg1) + " 秒");
break;
}
}
}
}
//模擬子線程進行耗時任務(wù)
private final Runnable mRunnable = new Runnable() {
@Override
public void run() {
//這里做的是一個倒計時定時一秒發(fā)送一次數(shù)據(jù)
for (int i = 60; i > 0; i--) {
//構(gòu)建屬于子線程的Message
Message msg = new Message();
msg.what = UPDATE;
msg.arg1 = i;
//通過主線程中的Handler實例進行消息發(fā)送管钳,將子線程中的消息發(fā)送到主線程中
mHandler.sendMessage(msg);
try {
//休眠1秒
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
//在當(dāng)前的線程中準(zhǔn)備一個消息輪詢器
Looper.prepare();
//創(chuàng)建主線程的Handler
mHandler = new MyHandler(this);
//開啟子線程運行耗時操作
new Thread(mRunnable).start();
//這里開啟消息輪詢器會造成UI的繪制阻塞
Looper.loop();
}
}
可以通過日志查看我們自己定義的Handler機制是可以實現(xiàn)線程之間通訊的。
至于我們自己編寫的Looper.loop();造成的阻塞問題我們后面在研究扫茅;