什么是Handler?
Handler主要用于異步消息的處理可婶,當發(fā)出一個消息后,首先進入一個消息隊列兜蠕,發(fā)送消息的函數(shù)即刻返回扰肌,而另外一個部分在消息隊列中逐一將消息取出抛寝,然后對消息進行處理熊杨。
子線程進行耗時操作>>>>>>>>>sendMessage(Message)>>>>>>>>UI線程
1.handler內(nèi)存泄漏測試
2.為什么不能在子線程創(chuàng)建handler
3.textview.setText(" ")只能在主線程執(zhí)行是錯誤的曙旭。
4.new handler()兩種寫法的區(qū)別
5.ThreadLocal的用法和原理
answer1 在子線程中發(fā)送消息時,如果要延時采用sendMessageDelayed(),當onDestory()時,removeMessage(),或者SyetemClock.sleep()系統(tǒng)延遲時晶府,在onDestory()時桂躏,將handler=null置空
answer2 其實在有些手機上面是可以的,因為廠商在底層修改了源碼川陆,但是原生系統(tǒng)中剂习,當new hander時,threadLocal回去threadLocalMap中去取looper较沪,而looper是全局的唯一變量已經(jīng)給了主線程鳞绕,當子線程再去去的時候就已經(jīng)取不到了。
answer3 其實setText(" ")執(zhí)行速度當刷新頁面的速度快于checkThread()的速度就不會拋異常尸曼,如果延時或者采用土司就會拋出異常们何。為了保險起見在子線程中不應該setText(" "),但是這種說法太過絕對。
answer4 一種是重寫handlerMessage(),另一種是將回調(diào)接口CallBack當作參數(shù)傳入new Handler構造方法控轿。
answer5 從threadLocalMap中獲取key value冤竹。key是線程,value是looper茬射。ThreadLocal有一個全局唯一靜態(tài)變量鹦蠕,當ThreadActivity創(chuàng)建時就已經(jīng)創(chuàng)建。
Handler原理在抛,工作流程
第一步:ActivityThread中的main(),Looper.prepareMainLooper()>>>>prepare()>>>>sThreadLocal.set(new Looper)創(chuàng)建全局唯一Looper對象钟病,在Looper構造方法中{new MessageQueue()}創(chuàng)建全局唯一消息隊列
第二步:在activity中,new Handler()重寫handlerMessage();在創(chuàng)建對象的過程中刚梭,將全局的messageQueue對象賦值給Handler中的messageQueue档悠,再從全局線程池中取出主線程Looper,sThreadLocal.get()。
?? 發(fā)送消息 handler.sendMessage(message)>>>>將消息放入隊列中望浩,queue.enqueueMessage(msg)>>>>mMeeages=msg?
?? 取消息 ActivityThread中的main(),looper.loop()中有一個輪詢器一直在工作//獲取looper對象 Looper me=getLooper(),獲取消息隊列辖所,MessageQueue queue=me.mQueue;//從消息隊列取出消息Message msg=mQueue.next();調(diào)用handler的方法,msg.targe.dispatchMessage(msg);
自己手寫Handler流程源碼,只是一個大致工作流程磨德,不考慮健壯性等因素
1.ActivityThread
public class ActivityThread {
@Test
? ? public void main() {
//創(chuàng)建全局唯一的,主線程的Looper對象缘回,以及messageQueue消息隊列對象。
? ? ? ? Looper.prepare();
? ? ? ? //模擬activity中典挑,創(chuàng)建handler對象
? ? ? ? final Handler handler =new Handler() {
@Override
? ? ? ? ? ? public void handlerMessage(Message message) {
super.handlerMessage(message);
? ? ? ? ? ? ? ? System.out.println(message.obj.toString());
? ? ? ? ? ? }
};
? ? ? ? //消費消息酥宴,回調(diào)方法(接口方法)
//子線程發(fā)送消息
? ? ? ? new Thread(new Runnable() {
@Override
? ? ? ? ? ? public void run() {
Message messa=new Message();
? ? ? ? ? ? ? ? messa.obj="hello handler";
? ? ? ? ? ? ? ? handler.sendMessage(messa);
? ? ? ? ? ? }
}).start();
? ? ? ? //輪詢。取出消息
? ? ? ? Looper.loop();
? ? }
}
2.Looper
public class Looper {
public MessageQueuemQueue;
? ? static final ThreadLocalsThreadLocal =new ThreadLocal<>();
? ? private Looper() {
mQueue =new MessageQueue();
? ? }
public static void prepare() {
//主線程唯一一個Loop對象
? ? ? ? if (sThreadLocal.get() !=null) {
throw new RuntimeException("Only one Looper may be created per thread");
? ? ? ? }
//應用啟動時您觉,初始化賦值
? ? ? ? sThreadLocal.set(new Looper());
? ? }
//輪詢拙寡,提取消息
? ? public static void loop() {
//從全局ThreadlocalMap()中獲取全局唯一Looper對象
? ? ? ? Looper me =getLooper();
? ? ? ? //從Looper對象中獲取全局唯一的消息隊列對象
? ? ? ? final MessageQueue queue = me.mQueue;
? ? ? ? Message resultMessage;
? ? ? ? while (true) {
Message msg = queue.next();
? ? ? ? ? ? if (msg !=null) {
msg.targe.dispatchMessage(msg);
? ? ? ? ? ? }
}
}
public static LoopergetLooper() {
return sThreadLocal.get();
? ? }
}
3.Message
public class Message {
public? Objectobj;
? public Handlertarge;
? ? @Override
? ? public StringtoString() {
return obj.toString();
? ? }
}
4.//消息隊列
public class MessageQueue {
//阻塞隊列
? ? BlockingQueueblockingQueue =new ArrayBlockingQueue<>(50);
? ? //將message存入消息隊列
? ? public void enqueueMessag(Message message) {
try {
blockingQueue.put(message);
? ? ? ? }catch (InterruptedException e) {
e.printStackTrace();
? ? ? ? }
}
//從消息隊列取出message
? ? public Messagenext() {
try {
return blockingQueue.take();
? ? ? ? }catch (InterruptedException e) {
e.printStackTrace();
? ? ? ? }
return null;
? ? }
}
5Handler
public class Handler {
private LoopermLooper;
? ? private MessageQueuemQueue;
? ? public Handler() {
mLooper = Looper.getLooper();
? ? ? ? if(mLooper==null){
throw? new RuntimeException("Can't create handler inside thread " + Thread.currentThread()
+" that has not called Looper.prepare()");
? ? ? ? }
mQueue=mLooper.mQueue;
? ? }
public void handlerMessage(Message message) {
}
public void sendMessage(Message message) {
enqueueMessage(message);
? ? }
private void enqueueMessage(Message message) {
message.targe=this;
? ? ? ? mQueue.enqueueMessag(message);
? ? }
public void dispatchMessage(Message msg) {
handlerMessage(msg);
? ? }
}