Handler定義以及作用
handler
是andorid
的一套消息傳遞機制,用於跨線程通信,主要用於工作線程與主線程間的交互。andorid
的UI
操作需要在主線程上操作,一般耗時都放到其它的子線程下操作。耗時操作返回的結果在UI
線程先的展示需要跨線程通信 這個時候就可以使用handler
來通信了
Handler使用流程圖
Handler原理圖
幾個關鍵的類:
- Message:數據單元,
MessageQueue
的一個個數據。 - Looper:
MessageQueue
跟Handler
的通信中間人。兩個作用:不斷循環從MessageQueue
中取出Message
,將Message
發送給對應的Handler
。 - MessageQueue:數據結構(先進先出)存儲
Message
- Handler:線程間通行的中間人,
Message
信息的邏輯處理者,將Message
發送到MessageQueue
,處理Looper
發送過來的Message
基礎使用
public class MainActivity extends AppCompatActivity {
//關鍵代碼1
private static class MyHander extends Handler{
private final WeakReference<MainActivity> mActivity ;
public MyHander(MainActivity activity){
mActivity = new WeakReference<MainActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (null != mActivity.get()) {
switch (msg.what){
case 1:
//關鍵代碼3
mActivity.get().toNotify();
break;
default:
break;
}
}
}
}
MyHander myHander;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//關鍵代碼2
myHander = new MyHander(this);
Button button = findViewById(R.id.btn);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//關鍵代碼3
Message message = myHander.obtainMessage();
message.what = 1;
message.obj = getString(R.string.text);
myHander.sendMessageDelayed(message,5000);
}
});
}
public void toNotify() {
....邏輯操作
}
}
關鍵代碼1: 先定義MyHanlder
繼承Handler
關鍵代碼2:新建myHandler
對象,將MainActivity
傳入MyHandler
,MyHandler
弱引用MainActivity
,所以MyHandler # handleMessage()
處理需要if (null != mActivity.get())
做一下對象null判斷
關鍵代碼3:構建Message
,可以從緩存池中獲取,也可以直接自己new Message
,併發送myHander.sendMessageDelayed(message,5000)
其實平時的寫法有些同學是在
MainActivity
中直接定義匿名內部類MyHander
那種做法會調來內存泄漏的風險。因爲匿名內部類引用着外部類,導致外部類被挾持,這就有可能導致內存泄漏了。
上面這種用法可以避免handler
挾持了外部類MainActivity
的引用
handler發送數據的兩種不同的形式
sendxxx()
的方法
看一下源碼幾種方法的區別:
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
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);
}
從上面可以看到,方法的最後都是調用到了sendMessageAtTime(Message msg, long uptimeMillis)
,看了一下上面的方法大家都懂各個方法的區別了。
主要是要注意一下使用的時候sendMessageAtTime(Message msg, long uptimeMillis)
跟sendMessageDelayed(Message msg, long delayMillis)
的區別,一個是當前的時刻,一個 當前的時刻+delayMillis
2.postxxx()
的方法
看一下源碼幾種方法的區別:
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean postAtFrontOfQueue(Runnable r)
{
return sendMessageAtFrontOfQueue(getPostMessage(r));
}
public final boolean postDelayed(Runnable r, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
public final boolean postDelayed(Runnable r, Object token, long delayMillis)
{
return sendMessageDelayed(getPostMessage(r, token), delayMillis);
}
public final boolean postAtTime(Runnable r, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
對應使用了sendxxx
的方法,主要看一下getPostMessage()
這個方法
這裏有個坑 要記得看一下:
Handler.post(Runnable)
其實就是生成一個what = 0
的Message
如果你先調用Handler.post(Runnable)
再調用發送任何一條what = 0
的Message
會導致原來的被remove
掉,從而看到一臉懵逼 具體的等下代碼解析再看一下https://www.cnblogs.com/coding-way/p/5110125.html
源碼解析
從主線程開始入手吧~
####ActivityThread
public final class ActivityThread extends ClientTransactionHandler {
final H mH = new H();
final Handler getHandler() {
return mH;
}
class H extends Handler {
......
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case BIND_APPLICATION:
......
break;
}
case EXIT_APPLICATION:
......
break;
}
}
public static void main(String[] args) {
Process.setArgV0("<pre-initialized>");
......
//關鍵代碼1
Looper.prepareMainLooper();
......
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
//關鍵代碼2
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
.......
//關鍵代碼3
Looper.loop();
}
關鍵代碼1:先調用Looper.prepareMainLooper()
關鍵代碼2:獲取sMainThreadHandler
,獲取ActivityThread
的mH
對象,mH
對象實現了handleMessage(Message msg)
方法
關鍵代碼3:Looper.loop()
開啓循環
我們先看一下關鍵代碼1 看一下Looper
這個類以及對象的調用方法()
Looper(部分源碼)
public final class Looper {
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
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));
}
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
......
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
......
try {
msg.target.dispatchMessage(msg);
}
......
}
}
}
Looper.prepareMainLooper()
:這個方法的相關調用流prepare(false)
->sThreadLocal.set(new Looper(quitAllowed));
->myLooper()
->sThreadLocal.get()
這裏產生了一個looper
並設置到sThreadLocal
中,獲取的時候也是從sThreadLocal
中去獲取。而且在prepare(false)
中做判斷,如果已經存在就不能再調用該方法,也就是說 一個線程中只能存在一個Looper
,且一個Looper
只能擁有一個mQueue
,則說明Looper
跟MessageQueue
是一對一關係Looper.loop()
:這個方法的相關調用流程me
->me.mQueue
->(for (;;)-> queue.next()->msg.target.dispatchMessage(msg)
)
開啓死循環不斷的輪訓MessageQueue
,msg.target
其實返回的是Handler
,使用Handler
發送數據
(關於ThreadLocal相關的,後面再加以補充)
接下來我們看一下Handler
發送數據dispatchMessage
這個方法
Handler (部分源碼)
public class Handler {
public Handler(Looper looper, Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
public interface Callback {
public boolean handleMessage(Message msg);
}
public void handleMessage(Message msg) {
}
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
private static Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain();
m.obj = token;
m.callback = r;
return m;
}
}
這裏你可以看到
dispatchMessage(Message msg)
中有三種不同的調用
handleCallback(msg)
:這個是處理Handler.postxxx(Runnable r,xx)
發送的信息處理,最終回到用到r
的run
方法裏面做邏輯處理handleMessage(msg)
跟mCallback.handleMessage(msg)
:都是用於處理Handler.sendxxx()
發送的信息,不同點在於,實例化Handler
有沒有傳入mCallback
對象,有的話則在mCallback.handleMessage
進行邏輯處理,沒有的話則在handleMessage
進行邏輯處理
看一下Message
這個類的一些屬性
Message(部分源碼)
public final class Message implements Parcelable {
public int what;
public int arg1;
public Object obj;
long when;
Bundle data;
Handler target;
Runnable callback;
Message next;
}
Message
擁有Handler
對象,所以來自不同的Handler
對象發送的Message
信息將自己也傳入進來。
###總結
Handler並將本身傳入到Messag中併發送到MessageQueue中,Looper開啓輪訓不斷輪訓MessageQueue的消息,將Message取出並使用Handler對象回調其本身的方法去進行邏輯操作。
Looper: 在第一次實例化的時候存到ThreadLocal變量中,並且獲取的時候有則返回無則創建,所以一個線程只存在一個Looper。
MessageQueue: 是在Looper的構造函數中創建的,並且作爲其成員變量,一個線程有且只有一個MessageQueue
Handler: 可以創建多個,線程中並沒有限制其創建的個數,並且在Message中挾持着對應的Handler,所以不同的Message會對應交由自己的挾持的Handaler進行邏輯的操作
Handler各種面試題一覽
(大家可以參考一下網友的這篇文章)https://blog.csdn.net/feather_wch/article/details/81136078