Handler用法及解析

Handler用法及解析nbsp nbsp 目录 1 handler 作用 nbsp 1 传递消息 Message2 子线程通知主线程更新 ui2 常用 api3 handler 使用避免内存泄露 nbsp 1 handler 怎么使用会产生内存泄露 nbsp 2 如何避免 handler 的内存泄露 nbsp 3 nbsp 雷区 4 handlerThrea nbsp handlerThrea 是什么 2 HandlerThrea 使用及销毁

 

 

目录

1.handler作用: 

1)传递消息Message

2)子线程通知主线程更新ui

2.常用api

3.handler使用避免内存泄露

 1)handler怎么使用会产生内存泄露?

 2)如何避免handler的内存泄露?

 3)  雷区

4.handlerThread

1)  handlerThread是什么?

2)HandlerThread使用及销毁

5.源码解析

1)Message消息

2)Looper

3)  MessageQueue消息队列

4)Handler

6.总结


1.handler作用: 

1)传递消息Message

//2种创建消息方法 //1.通过handler实例获取 Handler handler = new Handler(); Message message=handler.obtainMessage(); //2.通过Message获取 Message message=Message.obtain(); //源码中第一种获取方式其实也是内部调用了第二种: public final Message obtainMessage(){ return Message.obtain(this); }

不建议直接new Message,Message内部保存了一个缓存的消息池,我们可以用obtain从缓存池获得一个消息,Message使用完后系统会调用recycle回收,如果自己new很多Message,每次使用完后系统放入缓存池,会占用很多内存的。 

//传递的数据 Bundle bundle = new Bundle(); bundle.putString("msg", "传递我这个消息"); //发送数据 Message message = Message.obtain(); message.setData(bundle); //message.obj=bundle 传值也行 message.what = 0x11; handler.sendMessage(message); //数据的接收 final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == 0x11) { Bundle bundle = msg.getData(); String date = bundle.getString("msg"); } } };

2)子线程通知主线程更新ui

 //创建handler final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == 0x11) { //更新ui ...... } } }; new Thread(new Runnable() { @Override public void run() { //FIXME 这里直接更新ui是不行的 //还有其他更新ui方式,runOnUiThread()等 message.what = 0x11; handler.sendMessage(message); } }).start();

2.常用api

 //消息 Message message = Message.obtain(); //发送消息 new Handler().sendMessage(message); //延时1s发送消息 new Handler().sendMessageDelayed(message, 1000); //发送带标记的消息(内部创建了message,并设置msg.what = 0x1) new Handler().sendEmptyMessage(0x1); //延时1s发送带标记的消息 new Handler().sendEmptyMessageDelayed(0x1, 1000); //延时1秒发送消息(第二个参数为:相对系统开机时间的绝对时间,而SystemClock.uptimeMillis()是当前开机时间) new Handler().sendMessageAtTime(message, SystemClock.uptimeMillis() + 1000); //避免内存泄露的方法: //移除标记为0x1的消息 new Handler().removeMessages(0x1); //移除回调的消息 new Handler().removeCallbacks(Runnable); //移除回调和所有message new Handler().removeCallbacksAndMessages(null);

3.handler使用避免内存泄露

 1)handler怎么使用会产生内存泄露?

public class MainActivity extends AppCompatActivity { final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); ...... } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //activity被执行时,被延迟的这个消息存于主线程消息队列中1分钟, //此消息包含handler引用,而handler由匿名内部类创建,持有activity引用, //activity便不能正常销毁,从而泄露 handler.postDelayed(new Runnable() { @Override public void run() { ...... } }, 1000 * 60); } }

 2)如何避免handler的内存泄露?

public class MainActivity extends AppCompatActivity { //创建静态内部类 private static class MyHandler extends Handler{ //持有弱引用MainActivity,GC回收时会被回收掉. private final WeakReference 
   
     mAct; public MyHandler(MainActivity mainActivity){ mAct =new WeakReference 
    
      (mainActivity); } @Override public void handleMessage(Message msg) { MainActivity mainAct=mAct.get(); super.handleMessage(msg); if(mainAct!=null){ //执行业务逻辑 } } } private static final Runnable myRunnable = new Runnable() { @Override public void run() { //执行我们的业务逻辑 } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MyHandler myHandler=new MyHandler(this); //延迟5分钟后发送 myHandler.postDelayed(myRunnable, 1000 * 60 * 5); } } 
     
   

 3)  雷区

a)Handler.post(Runnable)其实就是生成一个what为0的Message,调用

myHandler.removeMessages(0);

会使runnable任务从消息队列中清除。

详细解释:https://www.cnblogs.com/coding-way/p/5110125.html(转)

b) 子线程直接创建Handler,抛异常Can’t create handler inside thread that has not called Looper.prepare()

原因是非主线程没有loop对象,所以要调用Looper.prepare()方法,而且如果主线程给子线程发送消息,还要调用一个Looper.loop()的方法(此方法保证消息队列中的消息被不停的拿出,并被处理)

class MyThread extends Thread{ @Override public void run() { super.run(); Looper.prepare(); Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); //处理消息 } }; Looper.loop(); } } 

c)activity如被finish,但是handler刚好还在处理消息,如果需要用的资源已被释放,则会出现空指针异常。

所以在ondestory中去remove掉我们要处理的事件,还是有必要的。不想处理就直接try catch或者判空。

d)有时候你会发现removeCallbacks会失效,不能从消息队列中移除。

出现这情况是activity切入后台,再回到前台,此时的runnable由于被重定义,就会和原先的runnable并非同一个对象。所以这么做,加上static即可

static Handler handler = new Handler(); static Runnable myRunnable = new Runnable() { @Override public void run() { //执行我们的业务逻辑 } };

这样,因为静态变量在内存中只有一个拷贝,保证runnable始终是同一个对象。

4.handlerThread

1)  handlerThread是什么?

(题外话:异步存在形式有thread,handlerThead,asyncTask,线程池,intentService)

handlerThread继承thread,不过内部比普通线程多了一个Looper

//内部Looper.prepare() @Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; }

2)HandlerThread使用及销毁

public class MainActivity extends AppCompatActivity { private HandlerThread thread; static Handler mHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //创建一个HandlerThread并启动它 thread = new HandlerThread("MyHandlerThread"); thread.start(); //使用HandlerThread的looper对象创建Handler mHandler = new Handler(thread.getLooper(), new Handler.Callback() { @Override public boolean handleMessage(Message msg) { //这个方法是运行在 handler-thread 线程中的,可以执行耗时操作,因此不能更新ui,要注意 if (msg.what == 0x1) { try { Thread.sleep(3000); Log.e("测试: ", "执行了3s的耗时操作"); } catch (InterruptedException e) { e.printStackTrace(); } //这个方法是运行在 handler-thread 线程中的,可以执行耗时操作,因此不能更新ui,要注意 // ((Button) MainActivity.this.findViewById(R.id.button)).setText("hello"); } return false; } }); //停止handlerthread接收事件 findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { thread.quit(); } }); //运行 mHandler.sendEmptyMessage(0x1); } }

上面demo中,只要调用了

mHandler.sendEmptyMessage(0x1);

就会开始执行任务

几个地方要注意:

a.handleMessage()可以做耗时操作,但是不能更新ui

b.如果不手动的调用HandlerThread.quit()或者HandlerThread..quitSafely()方法,HandlerThread会将持续的接收新的任务事件。

c.只有handleMessage()方法执行完,这轮的任务才算完成,HandlerThread才会去执行下一个任务。而且在此次执行时,即使手动的去调用quit()方法,HandlerThread的此次任务也不会停止。但是,会停止下轮任务的接收。

举例: //耗时任务换成这个,点击按钮执行quit()方法,发现此次任务依旧执行 for (int i = 0; i < ; i++) { Log.e("测试: ", "输出" +i); }

d.HandlerThread的2种停止接收事件的方法。

第一个就是quit(),实际上执行了MessageQueue中的removeAllMessagesLocked方法,该方法的作用是把MessageQueue消息池中所有的消息全部清空,无论是延迟消息(带Delayed的)还是非延迟消息。

第二个就是quitSafely(),执行了MessageQueue中的removeAllFutureMessagesLocked方法,该方法只会清空MessageQueue消息池中所有的延迟消息,并将消息池中所有的非延迟消息派发出去让Handler去处理,quitSafely相比于quit方法安全之处在于清空消息之前会派发所有的非延迟消息

MessageQueue中源码: void quit(boolean safe) { if (!mQuitAllowed) { throw new IllegalStateException("Main thread not allowed to quit."); } synchronized (this) { if (mQuitting) { return; } mQuitting = true; if (safe) { removeAllFutureMessagesLocked(); } else { removeAllMessagesLocked(); } // We can assume mPtr != 0 because mQuitting was previously false. nativeWake(mPtr); } }
举例: //quit方法后,即使发送新事件,也不会被接收 findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { thread.quit(); //发送新事件 mHandler.sendEmptyMessage(0x1); } );

e.即使多次执行mHandler.sendEmptyMessage(0x1),任务队列中的任务依然只能一个一个的被处理。上一任务结束,开始执行下一个。

日志显示:输出0-99的任务结束,才执行下个输出0-99的任务 08-09 20:17:05.552 12618-12762/com.bihucj.mcandroid E/测试:: 输出95 08-09 20:17:05.552 12618-12762/com.bihucj.mcandroid E/测试:: 输出96 08-09 20:17:05.552 12618-12762/com.bihucj.mcandroid E/测试:: 输出97 08-09 20:17:05.552 12618-12762/com.bihucj.mcandroid E/测试:: 输出98 08-09 20:17:05.552 12618-12762/com.bihucj.mcandroid E/测试:: 输出99 08-09 20:17:05.718 12618-12762/com.bihucj.mcandroid E/测试:: 输出0 08-09 20:17:05.718 12618-12762/com.bihucj.mcandroid E/测试:: 输出1 08-09 20:17:05.719 12618-12762/com.bihucj.mcandroid E/测试:: 输出2 08-09 20:17:05.719 12618-12762/com.bihucj.mcandroid E/测试:: 输出3 08-09 20:17:05.719 12618-12762/com.bihucj.mcandroid E/测试:: 输出4 08-09 20:17:05.719 12618-12762/com.bihucj.mcandroid E/测试:: 输出5

 

5.源码解析

说到源码,主要还是几个关键词。分别为Message,Looper,MessageQueue,Handler。还有Thread

先说Looper,MessageQueue,Handler3者关联的思路:

主线程-->prepareMainLooper()(内部调用prepare() ,去实例化Looper,Looper实例化同时创建了messagequeue,11对应关系)-->主线程中的handler获取当前线程的Looper-->3者关联

插播主线程ActivityThread: public static void main(String[] args) { ...... Looper.prepareMainLooper(); ...... //区别:子线程是创建handler; //主线程是通过getHandler()获取内部类实例 if(sMainThreadHandler==null){ sMainThreadHandler=thread.getHandler(); } ...... } private class H extends Handler{ ...... }

子线程-->直接通过Looper.prepare()去实例化Looper,Looper实例化同时创建了messagequeue(11对应关系) -->实例化Handler同时获取当前子线程的Looper-->3者关联

1)Message消息

public final class Message implements Parcelable { //用户定义的消息代码,以便接收者能够识别 public int what; //arg1和arg2是使用成本较低的替代品-也可以用来存储int值 public int arg1; public int arg2; //存放任意类型的对象 public Object obj; //消息触发时间 long when; //消息携带内容 Bundle data; //消息响应方 Handler target; //消息管理器,会关联到一个handler public Messanger replyTo; //回调方法 Runnable callback; //消息存储的链表。这样sPool就成为了一个Messages的缓存链表。 Message next; //消息池 private static Message sPool; //消息池的默认大小 private static final int MAX_POOL_SIZE = 50; //从消息池中获取消息 public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; //从sPool的表头拿出Message sPool = m.next; //将消息池的表头指向下一个Message m.next = null; //将取出消息的链表断开 m.flags = 0; // 清除flag----flag标记判断此消息是否正被使用(下方isInUse方法) sPoolSize--; //消息池可用大小进行减1 return m; } } return new Message(); //消息池为空-直接创建Message } //通过标记判断消息是否正被使用 boolean isInUse() { return ((flags & FLAG_IN_USE) == FLAG_IN_USE); } //5.0后为true,之前为false. private static boolean gCheckRecycle = true; public void recycle() { if (isInUse()) { if (gCheckRecycle) { throw new IllegalStateException("This message cannot be recycled because it is still in use."); } return; } recycleUnchecked(); //消息没在使用,回收 } //对于不再使用的消息,加入到消息池 void recycleUnchecked() { //将消息标示位置为IN_USE,并清空消息所有的参数。 flags = FLAG_IN_USE; what = 0; arg1 = 0; arg2 = 0; obj = null; replyTo = null; sendingUid = -1; when = 0; target = null; callback = null; data = null; synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; //当消息池没有满时,将Message加入消息池 sPoolSize++; //消息池可用大小加1 } } }

2)Looper

 https://blog.csdn.net/woshiluoye9/article/details/72544764 (转)

插播ThreadLocal: ThreadLocal是线程的局部变量, 是每一个线程所单独持有的,其他线程不能对其进行访问。

主线程和子线程中的Looper的初始化

public final class Looper { //内部消息队列MessageQueue final MessageQueue mQueue; //Looper所在的线程 final Thread mThread; //Looper的变量存储 static final ThreadLocal 
   
     sThreadLocal = new ThreadLocal 
    
      (); //主looper private static Looper sMainLooper; //私有构造方法,不能通过New实例化。 private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed);//创建与其绑定的消息队列MessageQueue mThread = Thread.currentThread(); //绑定当前线程 } //子线程的调用----->最终通过prepare(boolean)实例化Looper public static void prepare() { prepare(true); } //主线程的调用----->最终通过prepare(boolean)实例化Looper 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作为主looper } } public static @Nullable Looper myLooper() { return sThreadLocal.get(); } //quitAllowed代表是否允许退出,主线程调用为不允许退出,子线程为可退出 private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { //看出一个线程只能存在一个Looper-->则调用二次Looper.prepare抛出异常 throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed));//Looper的变量存储+实例化Looper } 
     
   

Loop()方法,循环取出messagequeue消息队列中的消息,并分发出去。再把分发后的Message回收到消息池,以便重复利用。

public static void loop() { final Looper me = myLooper(); //从存储区拿出looper if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; //获取Looper对象中的消息队列 ...... //进入loop的主循环方法 for (;;) { Message msg = queue.next(); //可能会阻塞 if (msg == null) { //没有消息,则退出循环 return; } ...... //target是handler,此处用于分发Message msg.target.dispatchMessage(msg); ...... msg.recycleUnchecked(); //将Message放入消息池 } }

Looper中的quit方法-->调用的还是messageQueue中的quit()

 public void quit() { mQueue.quit(false); }

3)  MessageQueue消息队列

a)主要参数和构造方法

public final class MessageQueue { //供native代码使用 @SuppressWarnings("unused") private long mPtr; //交给native层来处理的核心方法 private native static long nativeInit(); private native static void nativeDestroy(long ptr); private native void nativePollOnce(long ptr, int timeoutMillis); //阻塞操作 private native static void nativeWake(long ptr); private native static boolean nativeIsPolling(long ptr); private native static void nativeSetFileDescriptorEvents(long ptr, int fd, int events); Message mMessages; //消息队列是否可以退出 private final boolean mQuitAllowed; //构造方法 MessageQueue(boolean quitAllowed) { mQuitAllowed = quitAllowed; mPtr = nativeInit(); //通过native方法初始化消息队列,其中mPtr是供native代码使用 }

b)核心的next()方法

//不停提取下一条message Message next() { final long ptr = mPtr; //判断是否退出消息循环 if (ptr == 0) { return null; } int pendingIdleHandlerCount = -1; //代表下一个消息到来前,还需要等待的时长 int nextPollTimeoutMillis = 0; for (;;) { if (nextPollTimeoutMillis != 0) { Binder.flushPendingCommands(); } //native层阻塞cpu。如果被阻塞,唤醒事件队列 nativePollOnce(ptr, nextPollTimeoutMillis); synchronized (this) { final long now = SystemClock.uptimeMillis(); Message prevMsg = null; Message msg = mMessages; //如果当前消息是异步消息,都将赋值给prevMsg,过滤掉,直到取到了非异步消息 if (msg != null && msg.target == null) { do { prevMsg = msg; msg = msg.next; } while (msg != null && !msg.isAsynchronous()); } //获取到了非异步消息 if (msg != null) { //任务执行时间大于现在的时间 if (now < msg.when) { //设置下一次轮询的超时时长 nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE); } else { mBlocked = false;//指定为非阻塞任务 if (prevMsg != null) { prevMsg.next = msg.next; } else { mMessages = msg.next; } msg.next = null; //设置消息的使用状态,即flags |= FLAG_IN_USE msg.markInUse(); return msg; //成功地获取MessageQueue中的下一条即将要执行的消息 } } else { //表示消息队列中无消息,会一直等待下去 nextPollTimeoutMillis = -1; } ...... //IdleHandler为发现线程何时阻塞的回调接口 for (int i = 0; i < pendingIdleHandlerCount; i++) { final IdleHandler idler = mPendingIdleHandlers[i]; mPendingIdleHandlers[i] = null; //去除handler引用 boolean keep = false; //queueIdle返回true会被空闲的处理器处理,false就会被移走 try { keep = idler.queueIdle(); //idle时执行的方法 } catch (Throwable t) { Log.wtf(TAG, "IdleHandler threw exception", t); } if (!keep) { synchronized (this) { mIdleHandlers.remove(idler); //被移走 } } } //重置idle handler个数为0,保证不会再次重复运行 pendingIdleHandlerCount = 0; nextPollTimeoutMillis = 0; } }

next()方法中,做了异步Message消息的判断,特殊的是这个Message没有设置target,即msg.target为null。

c)核心的enqueueMessage()方法

boolean enqueueMessage(Message msg, long when) { // 每一个普通Message必须有一个target-handler 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) { msg.recycle(); return false; } //标记使用状态,记录执行时间 msg.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; //p为null代表MessageQueue没有消息或者msg的触发时间是队列中最早的 if (p == null || when == 0 || when < p.when) { msg.next = p; mMessages = msg; needWake = mBlocked; //当阻塞时需要唤醒 } else { //将消息按时间顺序插入到MessageQueue。 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; prev.next = msg; } if (needWake) { nativeWake(mPtr); } } return true; }

队列中的Message触发时间是有先后顺序的。当消息加入消息队列时,会从队列头开始遍历,直到找到消息应该插入的合适位置,以保证所有消息的时间顺序(内部遍历队列中Message,找到when比当前Message的when大的Message,将Message插入到该Message之前,如果没找到则将Message插入到队列最后)。一般是当前队列为空的情况下,next那边会进入睡眠,需要的时候MessageQueue这边会唤醒next方法。

d)removeMessages()和removeCallbacksAndMessages()方法

void removeMessages(Handler h, int what, Object object) { if (h == null) { return; } synchronized (this) { Message p = mMessages; //从消息队列的头部开始,移除所有符合条件的消息 while (p != null && p.target == h && p.what == what && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; p.recycleUnchecked(); p = n; } //移除剩余的符合要求的消息 while (p != null) { Message n = p.next; if (n != null) { if (n.target == h && n.what == what && (object == null || n.obj == object)) { Message nn = n.next; n.recycleUnchecked(); p.next = nn; continue; } } p = n; } } } void removeCallbacksAndMessages(Handler h, Object object) { if (h == null) { return; } synchronized (this) { Message p = mMessages; while (p != null && p.target == h && (object == null || p.obj == object)) { Message n = p.next; mMessages = n; p.recycleUnchecked(); p = n; } while (p != null) { Message n = p.next; if (n != null) { if (n.target == h && (object == null || n.obj == object)) { Message nn = n.next; n.recycleUnchecked(); p.next = nn; continue; } } p = n; } } }

4)Handler

a)主要参数和构造方法

public class Handler { final Looper mLooper; final MessageQueue mQueue; final Callback mCallback; //回调 final boolean mAsynchronous; //是否异步消息 IMessenger mMessenger; public interface Callback { //如果不需要进一步的处理,则返回True public boolean handleMessage(Message msg); } //有参构造 public Handler(Looper looper) { this(looper, null, false); } //有参构造 public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; } public Handler(Callback callback, boolean async) { //匿名类、内部类或本地类都必须申明为static,否则会警告可能出现内存泄露 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()); } } //从Looper类中的(ThreadLocal)获取Looper对象 mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException(""); } mQueue = mLooper.mQueue; //Looper取出消息队列 mCallback = callback; //回调 mAsynchronous = async; //设置消息是否为异步处理方式 } 

b)消息的发送:

https://img-blog.csdn.net/20180810163246914?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM3MzIxMDk4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70

1.post--->调用sendMessageDelayed public final boolean post(Runnable r){ return sendMessageDelayed(getPostMessage(r), 0); } 2.postAtTime--->调用sendMessageAtTime public final boolean postAtTime(Runnable r, long uptimeMillis){ return sendMessageAtTime(getPostMessage(r), uptimeMillis); } 3.postAtTime--->调用sendMessageAtTime public final boolean postAtTime(Runnable r, Object token, long uptimeMillis){ return sendMessageAtTime(getPostMessage(r, token), uptimeMillis); } 4.postDelayed--->调用sendMessageDelayed public final boolean postDelayed(Runnable r, long delayMillis){ return sendMessageDelayed(getPostMessage(r), delayMillis); } 5.postAtFrontOfQueue--->调用sendMessageAtFrontOfQueue public final boolean postAtFrontOfQueue(Runnable r){ return sendMessageAtFrontOfQueue(getPostMessage(r)); } 6.sendMessage--->调用sendMessageDelayed public final boolean sendMessage(Message msg){ return sendMessageDelayed(msg, 0); } 7.sendEmptyMessage--->调用sendEmptyMessageDelayed public final boolean sendEmptyMessage(int what){ return sendEmptyMessageDelayed(what, 0); } 8.sendEmptyMessageDelayed--->调用sendMessageDelayed public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); } 9.sendEmptyMessageAtTime--->调用sendMessageAtTime public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageAtTime(msg, uptimeMillis); } 10.sendMessageDelayed--->调用sendMessageAtTime public final boolean sendMessageDelayed(Message msg, long delayMillis){ if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } 11.sendMessageAtTime--->调用enqueueMessage 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); } 12.sendMessageAtFrontOfQueue--->调用enqueueMessage //FIXME 该方法通过设置消息的触发时间为0,从而使Message加入到消息队列的队头 public final boolean sendMessageAtFrontOfQueue(Message msg) { 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, 0); } 13.enqueueMessage调用MessageQueue中的enqueueMessage private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } //uptimeMillis为系统当前的运行时间 return queue.enqueueMessage(msg, uptimeMillis); }
if (mAsynchronous) { msg.setAsynchronous(true); }

可以看到enqueueMessage方法时,每次都判断是否是异步消息。这就和MessageQueue中的Next()判断联系到了一起。

 

c)消息的移除--都会调用消息队列中的移除方法

public final void removeCallbacks(Runnable r){ mQueue.removeMessages(this, r, null); } public final void removeCallbacks(Runnable r, Object token){ mQueue.removeMessages(this, r, token); } public final void removeMessages(int what) { mQueue.removeMessages(this, what, null); } public final void removeMessages(int what, Object object) { mQueue.removeMessages(this, what, object); } public final void removeCallbacksAndMessages(Object token) { mQueue.removeCallbacksAndMessages(this, token); }

d)handleMessage(处理消息)和 dispatchMessage(分发消息)

 //处理消息 public void handleMessage(Message msg) { } //分发消息 public void dispatchMessage(Message msg) { if (msg.callback != null) { //当Message存在回调方法,回调方法msg.callback.run() handleCallback(msg); } else { //当Handler存在Callback成员变量时,回调方法mCallback.handleMessage(); if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } //Handler子类通过覆写该方法来完成具体的逻辑 handleMessage(msg); } }

优先级:

Message的回调方法>Handler的回调方法>Handler的默认方法

6.总结

  1. Handler通过sendMessage()方法发送Message到MessageQueue队列
  2. 当前Thread中Looper通过调用loop(),不断取出达到触发条件的Message,通过对应target(Handler)的dispatchMessage()方法,将Message交给Handler的handleMessage()方法来处理。
  3. 一个线程对应一个Looper,一个Looper对应一个MessageQueue,一个MessageQueue可以对用多个Message。但是一个Message只能让一个handler来处理(就是Message中target所指定的handler)。

 

参考:

handler发送异步消息:https://blog.csdn.net/cdecde111/article/details/54670136

https://blog.csdn.net/woshiluoye9/article/details/72544764

http://gityuan.com/2015/12/26/handler-message-framework/

https://blog.csdn.net/iispring/article/details/47180325

https://blog.csdn.net/milllulei/article/details/80927539

https://www.cnblogs.com/angeldevil/p/3340644.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/213325.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午6:06
下一篇 2026年3月18日 下午6:06


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号