文章目录 Android源码解析--享元设计模式,handler消息传递机制(基于Android API 33 SDK分析)一. 定义1.1 享元模式Demo 二. Android中源码
使用共享对象可有效地支持大量的细粒度的对象
核心:对象复用。
火车票购票Demo
//火车票public class Ticket { private String from; private String to; public Ticket(String from, String to) { this.from = from; this.to = to; } public int getPrice() { return new Random().nextInt(100) + 20; }}
缓存对象在一个Map中。下面我们还会分析
//火车票查询工厂public class TicketFactory { public static Map<String, Ticket> sTicketMap = new HashMap<>(); public static Ticket getTicket(String from, String to) { String key = from + "-" + to + ""; Ticket ticket = sTicketMap.get(key); if (ticket != null) { return ticket; } ticket = new Ticket(from, to); sTicketMap.put(key, ticket); return ticket; }}
用法
val obtain = Message.obtain()
跟进去
public static Message obtain() { //防止多线程并发 synchronized (sPoolSync) { //从线程池取对象 if (sPool != null) { //链表取出每个Message对象 Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message(); }
这就是最明显的一个享元设计模式。
Android 开发一个知识点:UI 不能够在子线程中更新。
class DebugActivity : AppCompatActivity() { private val TAG = javaClass.simpleName private var handler: Handler = Handler(Looper.getMainLooper()) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } fun doSomething(){ thread { //耗时操作,得到结果,不能在这个线程更新 UI // Handler 将结果传递到主线程中,更新UI handler.post { //更新UI } } }}
我们跟进post函数
public final boolean post(@NonNull Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
Handler 传递了一个 Runnable给UI线程,装到一个 Message 对象中。
跟进sendMessageDelayed函数
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) { //当前 Handler 所在的消息队列 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); }
sendMessageDelayed 函数调用了 sendMessageAtTime函数,不手动传递 Looper 那么 Handler 持有的 Looper 就是当前线程的 Looper,也就是说在哪个线程创建的 Handler,就是哪个线程的 Looper。
在 getPostMessage 中的 Message 对象是Message.obtain()函数
Message m = Message.obtain();
分析下这段代码,
public static Message obtain() { //防止多线程并发 synchronized (sPoolSync) { //从线程池取对象 if (sPool != null) { //链表取出每个Message对象 Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message(); }
Message消息池没有使用 map 这样的容器,使用的是链表。
在这里插入图片描述
如何放到这个消息池里面呢?
我们看
Message 对象回收到消息池中
public void recycle() { //该消息还在使用 if (isInUse()) { if (GCheckRecycle) { throw new IllegalStateException("This message cannot be recycled because it " + "is still in use."); } return; } //消息添加到消息池中 recycleUnchecked(); }
跟进recycleUnchecked()
void recycleUnchecked() { // Mark the message as in use while it remains in the recycled object pool. // Clear out all other details. //清空消息状态 flags = FLAG_IN_USE; what = 0; arg1 = 0; arg2 = 0; obj = null; replyTo = null; sendingUid = UID_NONE; workSourceUid = UID_NONE; when = 0; target = null; callback = null; data = null;//回收消息到消息池中 synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } }
这里用链表当作了一个缓存池,存消息对象。每生成一条消息就会加入到链表在。
Android应用程序的入口实际上是ActivityThread,跟进去
public static void main(String[] args) { ......//创建Looper,UI线程的消息队列 Looper.prepareMainLooper();...... //启动应用程序 ActivityThread thread = new ActivityThread(); thread.attach(false, startSeq);//循环消息 Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }
Looper 从消息队列中取消息,处理消息。Handler不断地往消息队列中添加消息,消息不断地被处理。
那么Handler是如何关联消息队列
Handler 的构造函数
public Handler(@Nullable Callback callback, boolean async) { ...... mLooper = Looper.myLooper();//获取 Looper ...... mQueue = mLooper.mQueue;//获取消息队列 mCallback = callback; mAsynchronous = async; }
Handler 通过myLooper()来获取 Looper 对象,
跟进myLooper()
public static @Nullable Looper myLooper() { //myLooper通过sThreadLocal.get()获取 return sThreadLocal.get(); }
Looper对象存储在sThreadLocal中的,
@Deprecated public static void prepareMainLooper() { prepare(false); synchronized (Looper.class) { if (sMainLooper != null) { throw new IllegalStateException("The main Looper has already been prepared."); } sMainLooper = myLooper(); } }//prepare()方法中创建了一个 Looper 对象private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } //将该对象设置给了sThreadLocal,这样线程和队列就关联上了 sThreadLocal.set(new Looper(quitAllowed)); }
Handler和线程、线程的消息队列关联,Handler 发送的消息就会被执行在这个线程上。
调用 Looper 的 loop 函数,不断地从消息队列中取出、处理消息
public static void loop() { ...... //死循环 for (;;) { //取消息 if (!loopOnce(me, ident, thresholdOverride)) { return; } } }
跟进loopOnce
private static boolean loopOnce(final Looper me, final long ident, final int thresholdOverride) { //获取消息 (might block ) Message msg = me.mQueue.next(); // might block ...... try { //处理消息 msg.target.dispatchMessage(msg); if (observer != null) { observer.messageDispatched(token, msg); } dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0; } ...... //回收消息,也就是我们分析享元模式时提到的将 Message 添加到消息池的操作 msg.recycleUnchecked(); return true; }
看看next()核心代码
Message next() { ......//native层的事件 nativePollOnce(ptr, nextPollTimeoutMillis);...... 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; } ...... } }
next 函数从消息队列中依次取出消息,如果这个消息到了执行时间,那么就将这条消息返回给 Looper,队列链表的指针后移。
class DebugActivity : AppCompatActivity() { private val TAG = javaClass.simpleName override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) thread { val handler = Handler() } } }
分析:Looper 对象是 ThreadLocal,每个线程都有自己的Looper,要在子线程中创建 Handler 对象时,如果 Looper 为空,那么就会抛出异常。跟进Handler的构造方法看看
public Handler(@Nullable Callback callback, boolean async) { ...... //获取looper mLooper = Looper.myLooper(); if (mLooper == null) { //抛出异常 throw new RuntimeException( "Can't create handler inside thread " + Thread.currentThread() + " that has not called Looper.prepare()"); } ...... }
mLooper 对象为空,抛出异常。该线程中的Looper 对象还没有创建,在子线程中没有手动调用 Looper.prepare之前该线程的 Looper为空,解决方法就是在构造 Handler 之前为当前线程设置 Looper 对象。
class DebugActivity : AppCompatActivity() { private val TAG = javaClass.simpleName override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) thread { //绑定到 ThreadLocal中 Looper.prepare() val handler = Handler() //启动消息循环 Looper.loop() } }}
这样子线程的Looper对象就不会为null了,有了自己的消息队列。
来源地址:https://blog.csdn.net/weixin_46039528/article/details/132391529
--结束END--
本文标题: Android源码解析--享元设计模式,handler消息传递机制(基于Android API 33 SDK分析)
本文链接: https://lsjlt.com/news/384000.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-01-21
2023-10-28
2023-10-28
2023-10-27
2023-10-27
2023-10-27
2023-10-27
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0