日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
Android中Handler,MessageQueue與Looper關(guān)系是什么

這篇文章主要介紹了Android中Handler,MessageQueue與Looper關(guān)系是什么,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

創(chuàng)新互聯(lián)是一家專業(yè)提供會(huì)寧企業(yè)網(wǎng)站建設(shè),專注與網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)HTML5建站、小程序制作等業(yè)務(wù)。10年已為會(huì)寧眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)的建站公司優(yōu)惠進(jìn)行中。

一說到Android的消息機(jī)制,自然就會(huì)聯(lián)想到Handler,我們知道Handler是Android消息機(jī)制的上層接口,因此我們?cè)陂_發(fā)過程中也只需要和Handler交互即可,很多人認(rèn)為Handler的作用就是更新UI,這也確實(shí)沒錯(cuò),但除了更新UI,Handler其實(shí)還有很多其他用途,比如我們需要在子線程進(jìn)行耗時(shí)的I/O操作,可能是讀取某些文件或者去訪問網(wǎng)絡(luò)等,當(dāng)耗時(shí)操作完成后我們可能需要在UI上做出相應(yīng)的改變,但由于Android系統(tǒng)的限制,我們是不能在子線程更新UI控件的,否則就會(huì)報(bào)異常,這個(gè)時(shí)候Handler就可以派上用場(chǎng)了,我們可以通過Handler切換到主線程中執(zhí)行UI更新操作。

下面是Handler一些常用方法:

void handleMessage(Message msg):處理消息的方法,該方法通常會(huì)被重寫。

final boolean hasMessages(int what):檢測(cè)消息隊(duì)列中是否包含what屬性為指定值的消息。

Message obtainMessage():獲取消息的方法,此函數(shù)有多個(gè)重載方法。

sendEmptyMessage(int what):發(fā)送空消息。

final boolean sendEmptyMessageDelayed(int what , long delayMillis):指定多少毫秒后發(fā)送空消息。

final boolean sendMessage(Message msg):立即發(fā)送消息。

final boolean sendMessageDelayed(Message msg ,long delayMillis):指定多少毫秒后發(fā)送消息。

final boolean post(Runnable r):執(zhí)行runnable操作。

final boolean postAtTime(Runnable r, long upTimeMillis):在指定時(shí)間執(zhí)行runnable操作。

final boolean postDelayed(Runnable r, long delayMillis):指定多少毫秒后執(zhí)行runnable操作。

介紹完方法后,我們就從一個(gè)簡(jiǎn)單的例子入手吧,然后一步步的分析:

public class MainActivity extends AppCompatActivity {
 
 public static final int MSG_FINISH = 0X001;
 //創(chuàng)建一個(gè)Handler的匿名內(nèi)部類
 private Handler handler = new Handler() {
 
 @Override
 public void handleMessage(Message msg) {
  switch (msg.what) {
  case MSG_FINISH:
   LogUtils.e("handler所在的線程id是-->" + Thread.currentThread().getName());
   break;
  }
 }
 
 };
 
 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 //啟動(dòng)耗時(shí)操作
 consumeTimeThread(findViewById(R.id.tv));
// handler.post()
 }
 
 //啟動(dòng)一個(gè)耗時(shí)線程
 public void consumeTimeThread(View view) {
 new Thread() {
  public void run() {
  try {
   LogUtils.e("耗時(shí)子線程的Name是--->" + Thread.currentThread().getName());
   //在子線程運(yùn)行
   Thread.sleep(2000);
   //完成后,發(fā)送下載完成消息
   handler.sendEmptyMessage(MSG_FINISH);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
  }
 }.start();
 }
}

運(yùn)行結(jié)果:

Android中Handler,MessageQueue與Looper關(guān)系是什么

上面的例子其實(shí)就是Handler的基本使用,在主線中創(chuàng)建了一個(gè)Handler對(duì)象,然后通過在子線程中模擬一個(gè)耗時(shí)操作完成后通過sendEmptyMessage(int)方法發(fā)送一個(gè)消息通知主線程的Handler去執(zhí)行相應(yīng)的操作。通過運(yùn)行結(jié)果我們也可以知道Handler確實(shí)也是在主線程運(yùn)行的。

那么問題來了,通過Handler發(fā)送的消息是怎么到達(dá)主線程的呢?接下來我們就來掰掰其中的奧妙,前方高能,請(qǐng)集中注意力!為了更好的理解Handler的工作原理,我們先來介紹與Handler一起工作的幾個(gè)組件:

Message:Handler接收和處理消息的對(duì)象。

Looper:每個(gè)線程只能有一個(gè)Looper。它的loop方法負(fù)責(zé)讀取MessageQueue中的消息,讀到消息后把消息發(fā)送給Handler進(jìn)行處理。

MessageQueue:消息隊(duì)列,它采用先進(jìn)先出的方式來管理Message。程序創(chuàng)建Looper對(duì)象時(shí),會(huì)在它的構(gòu)造方法中創(chuàng)建MessageQueue對(duì)象。

Handler:它的作用有兩個(gè)—發(fā)送消息和處理消息,程序使用Handler發(fā)送消息,由Handler發(fā)送的消息必須被送到指定的MessageQueue;否則消息就沒有在MessageQueue進(jìn)行保存了。而MessageQueue是由Looper負(fù)責(zé)管理的,也就是說,如果希望Handler正常工作的話,就必須在當(dāng)前線程中有一個(gè)Looper對(duì)象。我們先對(duì)上面的幾個(gè)組件有大概的了解就好,后面我們都會(huì)詳細(xì)分析,既然消息是從Handler發(fā)送出去,那么我們就先從Handler入手吧。先來看看Handler 的構(gòu)造方法源碼:

public class Handler {
	/**
	 * 未實(shí)現(xiàn)的空方法handleMessage()
	 */
	public void handleMessage(Message msg) {
	}
	/**
	 * 我們通常用于創(chuàng)建Handler的構(gòu)造方法之一
	 */
	public Handler() {
		this(null, false);
	}
	// 構(gòu)造方法的內(nèi)調(diào)用的this(null, false)的具體實(shí)現(xiàn)
	public Handler(Callback callback, boolean async) {
//檢查Handler是否是static的,如果不是的,那么有可能導(dǎo)致內(nèi)存泄露
 if (FIND_POTENTIAL_LEAKS) { 
  final Class klass = getClass(); 
  if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && 
   (klass.getModifiers() & Modifier.STATIC) == 0) { 
  Log.w(TAG, "The following Handler class should be static or leaks might occur: " + 
   klass.getCanonicalName()); 
  } 
 } 
 //重要的組件出現(xiàn)啦!Looper我們先理解成一個(gè)消息隊(duì)列的管理者,用來從消息隊(duì)列中取消息的,后續(xù)會(huì)詳細(xì)分析
 mLooper = Looper.myLooper(); 
 if (mLooper == null) { 
  //這個(gè)異常很熟悉吧,Handler是必須在有Looper的線程上執(zhí)行,這個(gè)也就是為什么我在HandlerThread中初始化Handler 
  //而沒有在Thread里面初始化,如果在Thread里面初始化需要先調(diào)用Looper.prepare方法 
  throw new RuntimeException( 
  "Can't create handler inside thread that has not called Looper.prepare()"); 
 } 
 //將mLooper里面的消息隊(duì)列復(fù)制到自身的mQueue,這也就意味著Handler和Looper是公用一個(gè)消息隊(duì)列 
 mQueue = mLooper.mQueue; 
 //回調(diào)函數(shù)默認(rèn)是Null 
 mCallback = null; 
	}

分析:Handler的構(gòu)造方法源碼不是很多,也比較簡(jiǎn)單,但是我們從源碼中也可以得知,在創(chuàng)建Handler時(shí),Handler內(nèi)部會(huì)去創(chuàng)建一個(gè)Looper對(duì)象,這個(gè)Looper對(duì)象是通過Looper.myLooper()創(chuàng)建的(后續(xù)會(huì)分析這個(gè)方法),同時(shí)還會(huì)創(chuàng)建一個(gè)消息隊(duì)列MessageQueue,而這個(gè)MessageQueue是從Looper中獲取的,這也就意味著Handler和Looper共用一個(gè)消息隊(duì)列,當(dāng)然此時(shí)Handler,Looper以及MessageQueue已經(jīng)捆綁到一起了。上面還有一個(gè)情況要說明的,那就是:

if (mLooper == null) { 
 //這個(gè)異常很熟悉吧,Handler是必須在有Looper的線程上執(zhí)行,這個(gè)也就是為什么我在HandlerThread中初始化Handler 
 //而沒有在Thread里面初始化,如果在Thread里面初始化需要先調(diào)用Looper.prepare方法 
 throw new RuntimeException( 
 "Can't create handler inside thread that has not called Looper.prepare()"); 
 }

這里先回去判斷Looper是否為空,如果為null,那么就會(huì)報(bào)錯(cuò),這個(gè)錯(cuò)誤對(duì)我們來說應(yīng)該比較熟悉吧,那為什么會(huì)報(bào)這個(gè)錯(cuò)誤呢?我們?cè)谇懊嬲f過Handler的作用有兩個(gè)—發(fā)送消息和處理消息,我們?cè)谑褂肏andler發(fā)送消息,由Handler發(fā)送的消息必須被送到指定的MessageQueue;否則就無法進(jìn)行消息循環(huán)。而MessageQueue是由Looper負(fù)責(zé)管理的,也就是說,如果希望Handler正常工作的話,就必須在當(dāng)前線程中有一個(gè)Looper對(duì)象。那么又該如何保障當(dāng)前線程中一定有Looper對(duì)象呢?這里其實(shí)分兩種情況:

(1)在主UI線程中,系統(tǒng)已經(jīng)初始化好了一個(gè)Looper對(duì)象,因此我們可以直接創(chuàng)建Handler并使用即可。

(2)在子線程中,我們就必須自己手動(dòng)去創(chuàng)建一個(gè)Looper對(duì)象,并且去啟動(dòng)它,才可以使用Handler進(jìn)行消息發(fā)送與處理。使用事例如下:

class childThread extends Thread{
 public Handler mHandler;
 
 @Override
 public void run() {
  //子線程中必須先創(chuàng)建Looper
  Looper.prepare();
  
  mHandler =new Handler(){
  @Override
  public void handleMessage(Message msg) {
   super.handleMessage(msg);
   //處理消息
  }
  };
  //啟動(dòng)looper循環(huán)
  Looper.loop();
 }
 }

分析完Handler的構(gòu)造方法,我們接著看看通過Handler發(fā)送的消息到底是發(fā)送到哪里了?我們先來看看Handler的幾個(gè)主要方法源碼:

// 發(fā)送一個(gè)空消息的方法,實(shí)際上添加到MessagerQueue隊(duì)列中
public final boolean sendEmptyMessage(int what) {
	return sendEmptyMessageDelayed(what, 0);
}
// 給上一個(gè)方法調(diào)用
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
	Message msg = Message.obtain();
	msg.what = what;
	return sendMessageDelayed(msg, delayMillis);
}
// 給上一個(gè)方法調(diào)用
public final boolean sendMessageDelayed(Message msg, long delayMillis) {
	if (delayMillis < 0) {
		delayMillis = 0;
	}
	return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
// 給上一個(gè)方法調(diào)用
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);
}
// 最后調(diào)用此方法添加到消息隊(duì)列中
private boolean enqueueMessage(MessageQueue queue, Message msg,
		long uptimeMillis) {
	msg.target = this;// 設(shè)置發(fā)送目標(biāo)對(duì)象是Handler本身
	if (mAsynchronous) {
		msg.setAsynchronous(true);
	}
	return queue.enqueueMessage(msg, uptimeMillis);// 添加到消息隊(duì)列中
}
// 在looper類中的loop()方法內(nèi)部調(diào)用的方法
public void dispatchMessage(Message msg) {
	if (msg.callback != null) {
		handleCallback(msg);
	} else {
		if (mCallback != null) {
			if (mCallback.handleMessage(msg)) {
				return;
			}
		}
		handleMessage(msg);
	}
}

分析:通過源碼我們可以知道,當(dāng)我們調(diào)用sendEmptyMessage(int)發(fā)送消息后。最終Handler內(nèi)部會(huì)去調(diào)用enqueueMessage(MessageQueue queue,Message msg)方法把發(fā)送的消息添加到消息隊(duì)列MessageQueue中,同時(shí)還有設(shè)置msg.target=this此時(shí)就把當(dāng)前handler對(duì)象綁定到msg.target中了,這樣就完成了Handler向消息隊(duì)列存放消息的過程。這個(gè)還有一個(gè)要注意的方法 dispatchMessage(Message),這個(gè)方法最終會(huì)在looper中被調(diào)用(這里我們先知道這點(diǎn)就行,后續(xù)還會(huì)分析)。話說我們一直在說MessageQueue消息隊(duì)列,但這個(gè)消息隊(duì)列到底是什么???其實(shí)在Android中的消息隊(duì)列指的也是MessageQueue,MessageQueue主要包含了兩種操作,插入和讀取,而讀取操作本身也會(huì)伴隨著刪除操作,插入和讀取對(duì)應(yīng)的分別是enqueueMessage和next,其中enqueueMessage是向消息隊(duì)列中插入一條消息,而next的作用則是從消息隊(duì)列中取出一條消息并將其從隊(duì)列中刪除。雖然我們一直稱其為消息隊(duì)列但是它的內(nèi)部實(shí)現(xiàn)并不是隊(duì)列,而是通過一個(gè)單鏈表的數(shù)據(jù)結(jié)構(gòu)來維護(hù)消息列表的,因?yàn)槲覀冎绬捂湵碓诓迦牒蛣h除上比較有優(yōu)勢(shì)。至內(nèi)MessageQueue的內(nèi)部實(shí)現(xiàn),這個(gè)屬于數(shù)據(jù)結(jié)構(gòu)的范疇,我們就不過多討論了,還是回到原來的主題上來,到這里我們都知道Handler發(fā)送的消息最終會(huì)添加到MessageQueue中,但到達(dá)MessageQueue后消息又是如何處理的呢?還記得我們前面說過MessageQueue是由Looper負(fù)責(zé)管理的吧,現(xiàn)在我們就來看看Looper到底是如何管理MessageQueue的?

public final class Looper {
	// sThreadLocal.get() will return null unless you've called prepare().
	//存放線程的容器類,為確保獲取的線程和原來的一樣
	static final ThreadLocal sThreadLocal = new ThreadLocal();
	private static Looper sMainLooper; // guarded by Looper.class
	//消息隊(duì)列
	final MessageQueue mQueue;
	final Thread mThread;
	//perpare()方法,用來初始化一個(gè)Looper對(duì)象
	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));
	}
	//handler調(diào)用的獲取Looper對(duì)象的方法。實(shí)際是在ThreadLocal中獲取。
	public static Looper myLooper() {
		return sThreadLocal.get();
	}
		
	//Looper類的構(gòu)造方法,可以發(fā)現(xiàn)創(chuàng)建Looper的同時(shí)也創(chuàng)建了消息隊(duì)列MessageQueue對(duì)象
	private Looper(boolean quitAllowed) {
		mQueue = new MessageQueue(quitAllowed);
		mRun = true;
		mThread = Thread.currentThread();
	}
		
//這個(gè)方法是給系統(tǒng)調(diào)用的,UI線程通過調(diào)用這個(gè)線程,從而保證UI線程里有一個(gè)Looper 
//需要注意:如果一個(gè)線程是UI線程,那么myLooper和getMainLooper是同一個(gè)Looper 
 public static final void prepareMainLooper() { 
	prepare(); 
	setMainLooper(myLooper()); 
	if (Process.supportsProcesses()) { 
	 myLooper().mQueue.mQuitAllowed = false; 
	 } 
	} 
	 
//獲得UI線程的Looper,通常我們想Hanlder的handleMessage在UI線程執(zhí)行時(shí)通常會(huì)new Handler(getMainLooper()); 
 public synchronized static final Looper getMainLooper() { 
	 return mMainLooper; 
 } 
		
//looper中最重要的方法loop(),該方法是個(gè)死循環(huán),會(huì)不斷去消息隊(duì)列MessageQueue中獲取消息,然后調(diào)dispatchMessage(msg)方法去執(zhí)行
 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;
	 //死循環(huán)
	 for (;;) {
		Message msg = queue.next(); // might block
		if (msg == null) {
		// No message indicates that the message queue is quitting.
				return;
		}
//這里其實(shí)就是調(diào)用handler中的方法,而在Handler的源碼中也可以知道dispatchMessage(msg)內(nèi)部調(diào)用的就是handlerMessage()方法
		msg.target.dispatchMessage(msg);
		msg.recycle();
	}
}

分析:代碼不算多,我們拆分開慢慢說,在Looper源碼中我們可以得知其內(nèi)部是通過一個(gè)ThreadLocal的容器來存放Looper的對(duì)象本身的,這樣就可以確保每個(gè)線程獲取到的looper都是唯一的。那么Looper對(duì)象是如何被創(chuàng)建的呢?通過源碼我們可以知道perpare()方法就可以創(chuàng)建Looper對(duì)象:

//perpare()方法,用來初始化一個(gè)Looper對(duì)象
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));
}

在創(chuàng)建Looper對(duì)象前先會(huì)去判斷ThreadLocal中是否已經(jīng)存在Looper對(duì)象,如果不存在就新創(chuàng)建一個(gè)Looper對(duì)象并且存放ThreadLocal中。這里還有一個(gè)要注意的是在Looper創(chuàng)建的同時(shí)MessageQueue消息隊(duì)列也被創(chuàng)建完成,這樣的話Looper中就持有了MessageQueue對(duì)象。

//Looper類的構(gòu)造方法,可以發(fā)現(xiàn)創(chuàng)建Looper的同時(shí)也創(chuàng)建了消息隊(duì)列MessageQueue對(duì)象
	private Looper(boolean quitAllowed) {
		mQueue = new MessageQueue(quitAllowed);
		mRun = true;
		mThread = Thread.currentThread();
	}

那么我們?nèi)绾潍@取已經(jīng)創(chuàng)建好的Looper對(duì)象呢?通過源碼我們知道m(xù)yLooper()方法就可以獲取到Looper對(duì)象:

//handler調(diào)用的獲取Looper對(duì)象的方法。實(shí)際是在ThreadLocal中獲取。
	public static Looper myLooper() {
		return sThreadLocal.get();
	}

Looper對(duì)象的創(chuàng)建和獲取,還有MessageQueue對(duì)象的創(chuàng)建,現(xiàn)在我們都很清楚了,但是Looper到底是怎么管理MessageQueue對(duì)象的呢?這就要看looper()方法了:

//looper中最重要的方法loop(),該方法是個(gè)死循環(huán),
//會(huì)不斷去消息隊(duì)列MessageQueue中獲取消息,
//然后調(diào)dispatchMessage(msg)方法去執(zhí)行
 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;
	 //死循環(huán)
	 for (;;) {
		Message msg = queue.next(); // might block
		if (msg == null) {
		// No message indicates that the message queue is quitting.
				return;
		}
//這里其實(shí)就是調(diào)用handler中的方法,而在Handler的源碼中也可以知道dispatchMessage(msg)內(nèi)部調(diào)用的就是handlerMessage()方法
		msg.target.dispatchMessage(msg);
		msg.recycle();
	}

通過looper()方法內(nèi)部源碼我們可以知道,首先會(huì)通過myLoooper()去獲取一個(gè)Looper對(duì)象,如果Looper對(duì)象為null,就會(huì)報(bào)出一個(gè)我們非常熟悉的錯(cuò)誤提示,“No Looper;Looper.prepare() wasn't called on this thread”,要求我們先通過Looper.prepare()方法去創(chuàng)建Looper對(duì)象;如果Looper不為null,那么就會(huì)去獲取消息隊(duì)列MessageQueue對(duì)象,接著就進(jìn)入一個(gè)for的死循環(huán),不斷從消息隊(duì)列MessageQueue對(duì)象中獲取消息,如果消息不為空,那么久會(huì)調(diào)用msg.target的dispatchMessage(Message)方法,那么這個(gè)target又是什么,沒錯(cuò)target就是我們創(chuàng)建的Handler對(duì)象,還記得我們前面分析Handler源碼時(shí)說過的那個(gè)方法嘛?

// 在looper類中的loop()方法內(nèi)部調(diào)用的方法
public void dispatchMessage(Message msg) {
	if (msg.callback != null) {
		handleCallback(msg);
	} else {
		if (mCallback != null) {
			if (mCallback.handleMessage(msg)) {
				return;
			}
		}
		handleMessage(msg);
	}

現(xiàn)在明白了吧?首先,檢測(cè)Message的callback是否為null,不為null就通過handleCallback方法來處理消息,那么Message的callback是什么?其實(shí)就是一個(gè)Runnable對(duì)象,實(shí)際上就是Handler的post方法所傳遞的Runnable參數(shù),我們順便看看post方法源碼:

public final boolean post(Runnable r)
{
 return sendMessageDelayed(getPostMessage(r), 0);
 }

現(xiàn)在明白Message的callback是什么了吧?而對(duì)應(yīng)handleCallback方法邏輯也比較簡(jiǎn)單:

private static void handleCallback(Message message) {
 message.callback.run();
 }

嗯,是的,因此最終執(zhí)行的還是通過post方法傳遞進(jìn)來的Runnable參數(shù)的run方法。好了,我們繼續(xù)dispatchMessage()方法的分析,接著會(huì)去檢查mCallback是否為null,不為null,則調(diào)用mCallback的handleMessage方法來處理消息。至于Callback則就是一個(gè)接口定義如下:

/**
 * Callback interface you can use when instantiating a Handler to avoid
 * having to implement your own subclass of Handler.
 *
 * @param msg A {@link android.os.Message Message} object
 * @return True if no further handling is desired
 */
 public interface Callback {
 public boolean handleMessage(Message msg);
 }

這個(gè)接口有什么用呢?其實(shí)通過Callback接口我們就可以采取如下方法來創(chuàng)建Handler對(duì)象:

Handler handler =new Handler(callback)

那么這樣做到底有什么意義,其實(shí)這樣做可以用callback來創(chuàng)建一個(gè)Handler的實(shí)例而無需派生Handler的子類。在我們的開發(fā)過程中,我們經(jīng)常使用的方法就是派生一個(gè)Hanlder子類并重寫其handleMessage方法來處理具體的消息,而Callback給我們提供了另外一種方式,那就是當(dāng)我們不想派生子類的時(shí)候,可以通過Callback來實(shí)現(xiàn)。繼續(xù)dispatchMessage()方法的分析,最后如果以上條件都不成立的話,就會(huì)去調(diào)用Handler的handleMessage方法來處理消息。而 我們的Handler是在主線程創(chuàng)建的,也就是說Looper也是主線程的Looper,因此handleMessage內(nèi)部處理最終都會(huì)在主線程上執(zhí)行,就這樣整個(gè)流程都執(zhí)行完了。下面提供一個(gè)圖解幫助大家理解:

Android中Handler,MessageQueue與Looper關(guān)系是什么

最后我們來個(gè)小總結(jié):Android中的Looper類主要作用是來封裝消息循環(huán)和消息隊(duì)列的,用于在android線程中進(jìn)行消息處理。handler是用來向消息隊(duì)列中插入消息的并最好對(duì)消息進(jìn)行處理。

(1) Looper類主要是為每個(gè)線程開啟的單獨(dú)的消息循環(huán)。 默認(rèn)情況下android中新誕生的線程是沒有開啟消息循環(huán)的。(主線程除外,主線程系統(tǒng)會(huì)自動(dòng)為其創(chuàng)建Looper對(duì)象,開啟消息循環(huán)) Looper對(duì)象負(fù)責(zé)管理MessageQueue,而MessageQueue主要是用來存放handler發(fā)送的消息,而且一個(gè)線程只能有一個(gè)Looper,對(duì)應(yīng)一個(gè)MessageQueue。

(2) 我們通常是通過Handler對(duì)象來與Looper進(jìn)行交互的。Handler可看做是Looper的一個(gè)接口,用來向指定的Looper中的MessageQueue發(fā)送消息并且Handler還必須定義自己的處理方法。 默認(rèn)情況下Handler會(huì)與其被定義時(shí)所在線程的Looper綁定,如Handler在主線程中定義,它是與主線程的Looper綁定。 mainHandler = new Handler() 等價(jià)于 new Handler(Looper.myLooper())Looper.myLooper():獲取當(dāng)前進(jìn)程的looper對(duì)象, Looper.getMainLooper() 用于獲取主線程的Looper對(duì)象。

(3) 在非主線程中直接new Handler() 會(huì)報(bào)如下的錯(cuò)誤: Can't create handler inside thread that has not called Looper.prepare() 原因是非主線程中默認(rèn)沒有創(chuàng)建Looper對(duì)象,需要先調(diào)用Looper.prepare()啟用Looper,然后再調(diào)用Looper.loop()。

(4) Looper.loop():啟動(dòng)looper中的循環(huán)線程,Handler就會(huì)從消息隊(duì)列里取消息并進(jìn)行對(duì)應(yīng)處理。 最后要注意的是寫在Looper.loop()之后的代碼不會(huì)被執(zhí)行,這個(gè)函數(shù)內(nèi)部應(yīng)該是一個(gè)循環(huán),當(dāng)調(diào)用mHandler.getLooper().quit()后,loop()才會(huì)中止,其后的代碼才能得以運(yùn)行。

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“Android中Handler,MessageQueue與Looper關(guān)系是什么”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來學(xué)習(xí)!


文章標(biāo)題:Android中Handler,MessageQueue與Looper關(guān)系是什么
分享鏈接:http://www.dlmjj.cn/article/pspehi.html