我所知道的Handler

这篇具有很好参考价值的文章主要介绍了我所知道的Handler。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简单讲,handler就是两个功能

插入消息,enqueuemessage,msg,when
从消息队列中遍历所有消息,比对msg.when和当前的when,找到合适的位置插入

处理消息,looper.loop会从messagequeue中调用next。取消息,如果消息还没到时间该执行,就会比对时间,下次轮询就通过binder写入,native函数休眠,到时间唤醒执行。

handler内存泄漏

GCRoot 一般是静态变量或者常量可以作为GCROOT
GCROOT 是ThreadLocal,存在于Looper中,Looper被加载就存在,
handler持有activity或者fragment,handler又被message持有,message的target属性,message被messagequeue持有,messagequeue被looper中的threadlocal持有

java中匿名内部类会默认持有外部类的引用

打断持有链

  1. handler.removemesage handler.removecallbacks
  2. handler使用static修饰。

主线程的Looper不允许退出

处理消息,looper取出来后,调用message.tager.dispatchemesage后面调用了handler的handlemessage方法。

还有个callback对象,如果有callback,dispatch会先执行callback的处理,calllback返回true,后面就不处理了,callback返回false就给handler的handlemessage处理了

Meesage对象创建

message创建用的obtain,池化,频繁的创建销毁会导致内存不稳定,抖动,造成卡顿 oom等问题

message pool的最大缓存50

阻塞和休眠,阻塞是被动的,休眠是主动的,阻塞不会让出cpu,休眠会,thread.yield会让出cpu。

子线程主线程通信

handler,livedata,eventbus,flow,rxjava,broadcast,观察者模式不能跨线程

最终都是handler完成的。

Handler监听卡顿

原理是在looper内完成的,looper处理消息的时候,会打印内容,就是Printer,looper可以设置它。

Message消息的分类

同步消息,普通的消息都是同步消息
异步消息,创建handler的时候设置async为true即可
同步屏障,需要通过反射调用,app层无法直接调用,是messagequeue提供的posSyncBarrier方法实现的,返回一个token,时msg的arg1值,用它来取消同步屏障。和普通消息的区别是,msg。target属性为null。

刷新UI的消息是异步消息,发送前先插入了一个同步屏障消息,异步消息处理完成后,要将同步屏障消息移除队列

消息入队

handler消息加入队列,有一系列方法,如下:

// 发送空消息
public final boolean sendEmptyMessage(int what){}
public final boolean sendEmptyMessageDelayed(int what,long delay){}
public final boolean sendEmptyMessageAtTime(int what,long when){}
// 发送消息
public final boolean sendMessage(@NonNull Message msg){}
public final boolean sendMessageDelayed(@NonNull Message msg,long time){}
public final boolean sendMessageAtTime(@NonNull Message msg,long when){}

public final boolean sendMessageAtFrontOfQueue(Message msg) {}
// post发送
public final boolean post(@NonNull Runnable r) {}
public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {}
public final boolean postAtTime(  
@NonNull Runnable r, @Nullable Object token, long uptimeMillis) {}
public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {}
public final boolean postDelayed(Runnable r, int what, long delayMillis) {}
public final boolean postDelayed(  
        @NonNull Runnable r, @Nullable Object token, long delayMillis) {}
public final boolean postAtFrontOfQueue(@NonNull Runnable r) {}

// enqueue
public final boolean executeOrSendMessage(@NonNull Message msg) {}
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,  
        long uptimeMillis) {}

最终都是掉用的enqueueMessage加入队列

private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,  
        long uptimeMillis) {  
    msg.target = this;  // 绑定消息处理对象
    msg.workSourceUid = ThreadLocalWorkSource.getUid();  
  
    if (mAsynchronous) { // 根据handler创建是否是异步的,来将消息标记为异步消息 
        msg.setAsynchronous(true);  
    }  
    // 调用messagequeue的方法,加入队列。
    return queue.enqueueMessage(msg, uptimeMillis);  
}

下面看下消息如何入队的

boolean enqueueMessage(Message msg, long when) {  
    if (msg.target == null) {  
        throw new IllegalArgumentException("Message must have a target.");  
    }  
  
    synchronized (this) {  
        if (msg.isInUse()) {  
            throw new IllegalStateException(msg + " This message is already in use.");  
        }  
  
        if (mQuitting) {  
            IllegalStateException e = new IllegalStateException(  
                    msg.target + " sending message to a Handler on a dead thread");  
            Log.w(TAG, e.getMessage(), e);  
            msg.recycle();  
            return false;  
        }  
  
        msg.markInUse();  
        msg.when = when;  
        // 当前队列的头
        Message p = mMessages;  
        boolean needWake;  
        if (p == null || when == 0 || when < p.when) {  
            // New head, wake up the event queue if blocked.  
            // 消息队列为null,或者消息是立刻执行的,或者要执行的时间先于头消息的时间,将当前消息作为新的队列的头
            msg.next = p;  
            mMessages = msg;  
            needWake = mBlocked;  
        } else {  
            // Inserted within the middle of the queue.  Usually we don't have to wake  
            // up the event queue unless there is a barrier at the head of the queue            // and the message is the earliest asynchronous message in the queue.            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; // invariant: p == prev.next  
            prev.next = msg;  
        }  
		// 如果需要的话,唤醒队列,开始处理消息,就是MessageQueue的next方法开始执行
        // We can assume mPtr != 0 because mQuitting is false.  
        if (needWake) {  
            nativeWake(mPtr);  
        }  
    }  
    return true;  
}

取消息以及消息处理

取消息1

取消息入口是Looper的loop方法处理的

public static void loop() {  
    final Looper me = myLooper();  
    if (me == null) {  
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");  
    }  
    if (me.mInLoop) {  
        Slog.w(TAG, "Loop again would have the queued messages be executed"  
                + " before this one completed.");  
    }  
  
    me.mInLoop = true;  
  
    // Make sure the identity of this thread is that of the local process,  
    // and keep track of what that identity token actually is.    Binder.clearCallingIdentity();  
    final long ident = Binder.clearCallingIdentity();  
  
    // Allow overriding a threshold with a system prop. e.g.  
    // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'    final int thresholdOverride =  
            SystemProperties.getInt("log.looper."  
                    + Process.myUid() + "."  
                    + Thread.currentThread().getName()  
                    + ".slow", 0);  
  
    me.mSlowDeliveryDetected = false;  
	// 无限循环,通过loopOnce取消息
    for (;;) {  
        if (!loopOnce(me, ident, thresholdOverride)) {  
            return;  
        }  
    }  
}

处理消息

private static boolean loopOnce(final Looper me,  
        final long ident, final int thresholdOverride) {  
    // 取消息
    Message msg = me.mQueue.next(); // might block  
    if (msg == null) {  
        // No message indicates that the message queue is quitting.  
        return false;  
    }  
  
    // This must be in a local variable, in case a UI event sets the logger  
    final Printer logging = me.mLogging;  
    if (logging != null) {  
        logging.println(">>>>> Dispatching to " + msg.target + " "  
                + msg.callback + ": " + msg.what);  
    }  
    // Make sure the observer won't change while processing a transaction.  
    final Observer observer = sObserver;  
  
    final long traceTag = me.mTraceTag;  
    long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;  
    long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;  
    if (thresholdOverride > 0) {  
        slowDispatchThresholdMs = thresholdOverride;  
        slowDeliveryThresholdMs = thresholdOverride;  
    }  
    final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);  
    final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);  
  
    final boolean needStartTime = logSlowDelivery || logSlowDispatch;  
    final boolean needEndTime = logSlowDispatch;  
  
    if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {  
        Trace.traceBegin(traceTag, msg.target.getTraceName(msg));  
    }  
  
    final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;  
    final long dispatchEnd;  
    Object token = null;  
    if (observer != null) {  
        token = observer.messageDispatchStarting();  
    }  
    long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);  
    try {  
	    // 这里取出msg的target属性,就是handler对象,进行消息的处理。注意:屏障消息是没有target的。
        msg.target.dispatchMessage(msg);  
        if (observer != null) {  
            observer.messageDispatched(token, msg);  
        }  
        dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;  
    } catch (Exception exception) {  
        if (observer != null) {  
            observer.dispatchingThrewException(token, msg, exception);  
        }  
        throw exception;  
    } finally {  
        ThreadLocalWorkSource.restore(origWorkSource);  
        if (traceTag != 0) {  
            Trace.traceEnd(traceTag);  
        }  
    }  
    if (logSlowDelivery) {  
        if (me.mSlowDeliveryDetected) {  
            if ((dispatchStart - msg.when) <= 10) {  
                Slog.w(TAG, "Drained");  
                me.mSlowDeliveryDetected = false;  
            }  
        } else {  
            if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",  
                    msg)) {  
                // Once we write a slow delivery log, suppress until the queue drains.  
                me.mSlowDeliveryDetected = true;  
            }  
        }  
    }  
    // 这里会打印那些执行慢的消息
    if (logSlowDispatch) {  
        showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);  
    }  
  
    if (logging != null) {  
        logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);  
    }  
  
    // Make sure that during the course of dispatching the  
    // identity of the thread wasn't corrupted.    final long newIdent = Binder.clearCallingIdentity();  
    if (ident != newIdent) {  
        Log.wtf(TAG, "Thread identity changed from 0x"  
                + Long.toHexString(ident) + " to 0x"  
                + Long.toHexString(newIdent) + " while dispatching to "  
                + msg.target.getClass().getName() + " "  
                + msg.callback + " what=" + msg.what);  
    }  
  
    msg.recycleUnchecked();  
  
    return true;  
}

取消息2

再看下实际的取消息的方法,MessageQueue的next方法

Message next() {  
    // Return here if the message loop has already quit and been disposed.  
    // This can happen if the application tries to restart a looper after quit    // which is not supported.    
    final long ptr = mPtr;  
    if (ptr == 0) {  
        return null;  
    }  
  
    int pendingIdleHandlerCount = -1; // -1 only during first iteration  
    int nextPollTimeoutMillis = 0;  
    for (;;) {  
        if (nextPollTimeoutMillis != 0) {  
            Binder.flushPendingCommands();  
        }  
		// 这个方法会在没有消息的时候阻塞
        nativePollOnce(ptr, nextPollTimeoutMillis);  
  
        synchronized (this) {  
            // Try to retrieve the next message.  Return if found.  
            final long now = SystemClock.uptimeMillis();  
            Message prevMsg = null;
            // 消息头保存
            Message msg = mMessages;  
            if (msg != null && msg.target == null) {  
                // Stalled by a barrier.  Find the next asynchronous message in the queue.  
                // 这里处理同步屏障消息,如果当前消息是异步消息,就跳出循环,否则继续循环
                do {  
                    prevMsg = msg;  
                    msg = msg.next;  
                } while (msg != null && !msg.isAsynchronous()); 
                // 循环的作用,找出队列里的异步消息,存储在msg里,或者将同步屏障消息存储在msg中,prevMsg存储的是同步消息 
            }  
            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(); 
                    // 将取出的消息交给handler处理。 
                    return msg;  
                }  
            } else {  
                // No more messages.  
                nextPollTimeoutMillis = -1;  
            }  
  
            // Process the quit message now that all pending messages have been handled.  
            if (mQuitting) {  
                dispose();  
                return null;  
            }  
  
            // If first time idle, then get the number of idlers to run.  
            // Idle handles only run if the queue is empty or if the first message            // in the queue (possibly a barrier) is due to be handled in the future.            
            if (pendingIdleHandlerCount < 0  
                    && (mMessages == null || now < mMessages.when)) {  
                pendingIdleHandlerCount = mIdleHandlers.size();  
            }  
            if (pendingIdleHandlerCount <= 0) {  
                // No idle handlers to run.  Loop and wait some more.  
                mBlocked = true;  
                continue;  
            }  
  
            if (mPendingIdleHandlers == null) {  
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];  
            }  
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);  
        }  
  
        // Run the idle handlers.  
        // We only ever reach this code block during the first iteration.        
        for (int i = 0; i < pendingIdleHandlerCount; i++) {  
            final IdleHandler idler = mPendingIdleHandlers[i];  
            mPendingIdleHandlers[i] = null; // release the reference to the handler  
  
            boolean keep = false;  
            try {  
                keep = idler.queueIdle();  
            } catch (Throwable t) {  
                Log.wtf(TAG, "IdleHandler threw exception", t);  
            }  
  
            if (!keep) {  
                synchronized (this) {  
                    mIdleHandlers.remove(idler);  
                }  
            }  
        }  
  
        // Reset the idle handler count to 0 so we do not run them again.  
        pendingIdleHandlerCount = 0;  
  
        // While calling an idle handler, a new message could have been delivered  
        // so go back and look again for a pending message without waiting.        
        nextPollTimeoutMillis = 0;  
    }  
}

handler的消息处理

是从dispatchMessage方法开始的,里面进行消息处理

public void dispatchMessage(@NonNull Message msg) {
	// 检查message是否设置了callback对象(runnable类型的)
	if (msg.callback != null) {
		// 执行其run方法
		handleCallback(msg);
	} else {
		// 检查handler是否设置了callback对象
		if (mCallback != null) {
			if (mCallback.handleMessage(msg)) {
				// 如果返回true,后续就不执行了。
				return;
			}
		}
		// 自定义handler的时候,实现该方法处理消息
		handleMessage(msg);
	}
}

IdleHandler是什么?干什么?继续看MessageQueue类。

IdleHandler是MessageQueue的静态内部接口。如下

public static interface IdleHandler {  
    /**  
     * Called when the message queue has run out of messages and will now     * wait for more.  Return true to keep your idle handler active, false     * to have it removed.  This may be called if there are still messages     * pending in the queue, but they are all scheduled to be dispatched     * after the current time.     */   
    
     boolean queueIdle();  
}

当前线程的消息对立内当前没有消息要处理时,会取出idlehander执行任务,因为执行在主线程,禁止执行耗时操作。返回true表示执行完并不会移除该对象,false执行完一次就移除。
而且,执行时机是不确定的。
执行的地方在next方法内部。

Message next() {  
    // Return here if the message loop has already quit and been disposed.  
    // This can happen if the application tries to restart a looper after quit    // which is not supported.   
    final long ptr = mPtr;  
    if (ptr == 0) {  
        return null;  
    }  
  
    int pendingIdleHandlerCount = -1; // -1 only during first iteration  
    int nextPollTimeoutMillis = 0;  
    for (;;) {  
        if (nextPollTimeoutMillis != 0) {  
            Binder.flushPendingCommands();  
        }  
  
        nativePollOnce(ptr, nextPollTimeoutMillis);  
  
        synchronized (this) {  
            // Try to retrieve the next message.  Return if found.  
            final long now = SystemClock.uptimeMillis();  
            Message prevMsg = null;  
            Message msg = mMessages;  
            if (msg != null && msg.target == null) {  
                // Stalled by a barrier.  Find the next asynchronous message in the queue.  
                do {  
                    prevMsg = msg;  
                    msg = msg.next;  
                } while (msg != null && !msg.isAsynchronous());  
            }  
            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;  
            }  
  
            // Process the quit message now that all pending messages have been handled.  
            if (mQuitting) {  
                dispose();  
                return null;  
            }  
			// 执行到这里,说明没有找到message对象需要执行了,且线程没有退出。
            // If first time idle, then get the number of idlers to run.  
            // Idle handles only run if the queue is empty or if the first message            // in the queue (possibly a barrier) is due to be handled in the future.            
            if (pendingIdleHandlerCount < 0  
                    && (mMessages == null || now < mMessages.when)) {  
                pendingIdleHandlerCount = mIdleHandlers.size();  
            }  
            if (pendingIdleHandlerCount <= 0) {  
                // No idle handlers to run.  Loop and wait some more.  
                mBlocked = true;  
                continue;  
            }  
			// 取出idlehandlers
            if (mPendingIdleHandlers == null) {  
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];  
            }  
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);  
        }  
  
        // Run the idle handlers.  
        // We only ever reach this code block during the first iteration.  
        for (int i = 0; i < pendingIdleHandlerCount; i++) {  
            final IdleHandler idler = mPendingIdleHandlers[i];  
            mPendingIdleHandlers[i] = null; // release the reference to the handler  
  
            boolean keep = false;  
            try {  
	            // 执行idlehandler的方法
                keep = idler.queueIdle();  
            } catch (Throwable t) {  
                Log.wtf(TAG, "IdleHandler threw exception", t);  
            }  
  
            if (!keep) { 
	            // 需要移除的话,在此处进行移除
                synchronized (this) {  
                    mIdleHandlers.remove(idler);  
                }  
            }  
        }  
  
        // Reset the idle handler count to 0 so we do not run them again.  
        pendingIdleHandlerCount = 0;  
  
        // While calling an idle handler, a new message could have been delivered  
        // so go back and look again for a pending message without waiting.          
        nextPollTimeoutMillis = 0;  
    }  
}

补充,同步屏障消息的入队与出队

入队方法由MessageQueue提供,并且标记不对用户app开放访问

@UnsupportedAppUsage  
@TestApi  
public int postSyncBarrier() {  
    return postSyncBarrier(SystemClock.uptimeMillis());  
}  
  
private int postSyncBarrier(long when) {  
    // Enqueue a new sync barrier token.  
    // We don't need to wake the queue because the purpose of a barrier is to stall it.    synchronized (this) {  
        final int token = mNextBarrierToken++;  
        final Message msg = Message.obtain();  
        msg.markInUse();  
        msg.when = when;  
        msg.arg1 = token; // token标记,当处理完异步消息之后,要根据这个token移除屏障消息的 
  
        Message prev = null;  
        Message p = mMessages;  
        // 插入到消息对列中
        if (when != 0) {  
            while (p != null && p.when <= when) {  
                prev = p;  
                p = p.next;  
            }  
        }  
        if (prev != null) { // invariant: p == prev.next  
            msg.next = p;  
            prev.next = msg;  
        } else {  
            msg.next = p;  
            mMessages = msg;  
        }  
        return token;  
    }  
}

出队文章来源地址https://www.toymoban.com/news/detail-448385.html

@UnsupportedAppUsage  
@TestApi  
public void removeSyncBarrier(int token) {  
    // Remove a sync barrier token from the queue.  
    // If the queue is no longer stalled by a barrier then wake it.    synchronized (this) {  
        Message prev = null;  
        Message p = mMessages;  
        while (p != null && (p.target != null || p.arg1 != token)) {  
            prev = p;  
            p = p.next;  
        }  
        if (p == null) {  
            throw new IllegalStateException("The specified message queue synchronization "  
                    + " barrier token has not been posted or has already been removed.");  
        }  
        final boolean needWake;  
        if (prev != null) {  
            prev.next = p.next;  
            needWake = false;  
        } else {  
            mMessages = p.next;  
            needWake = mMessages == null || mMessages.target != null;  
        }  
        p.recycleUnchecked();  
  
        // If the loop is quitting then it is already awake.  
        // We can assume mPtr != 0 when mQuitting is false.        if (needWake && !mQuitting) {  
            nativeWake(mPtr);  
        }  
    }  
}

到了这里,关于我所知道的Handler的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android Handler机制

    Android Handler 机制是一种用于在 Android 应用中处理多线程和异步操作的机制。 为了解决UI线程(主线程)和后台线程之间的通信和异步处理的问题。在Android应用中,特别是在UI开发中,有一些重要的原则需要遵循: 主线程负责UI更新:  Android UI框架是单线程模型的,也就是说

    2024年02月19日
    浏览(39)
  • Android:Handler

    参考来源 参考来源 参考来源 参考来源 Binder/Socket用于进程间通信,而Handler消息机制用于同进程的线程间通信 handler机制是android系统运行的基础,它采用生产者,消费者模式进行设计。其中生产者和消费者都是handler,多个handler会生产消息message投递到线程共享的messagequeue有序

    2024年02月02日
    浏览(33)
  • 详解Handler

    本来按照《Android开发艺术探索》的进度我应该现在该看线程和线程池了,但是突然觉得Handler那块还有好多东西没有看,要是一并写到 线程和线程池 那块有点头重脚轻,所以还是单独写一篇博客,详细解数一下 Handler Handler的主要作用是将一个任务从它自己的线程切换到某个指定中

    2024年02月08日
    浏览(30)
  • Android handler用法及分析

    这里将handler机制中的message,looper和messagequeue分开分析,分开了解之后,会在进行一个总结。先来看handler里面都有哪些方法都做了哪些事情, hide方法和带有@UnsupportedAppUsage注释的方法(此方法不对外暴露使用)暂不描述 。 handler要传递的callback接口在handler类里面,该接口里面

    2024年02月05日
    浏览(46)
  • 安卓架构核心Handler原理解析

    当使用 handler 去发送一个消息的时候,查看调用栈,发现最终会调用到 MessageQueue.equeueMessage ,那么说既然是个 queue 肯定就有增和删, equeueMessage 就对应它的增,再看看是谁在调用 MessageQueue 。 不妨猜想一下,既然平常写这个 handler 都在主线程,而且主线程的入口就在 main ,

    2023年04月09日
    浏览(34)
  • Android的消息机制--Handler

    Android的消息机制是由Handler、Message、MessageQueue,Looper四个类支撑,撑起了Android的消息通讯机制,Android是一个消息驱动系统,由这几个类来驱动消息与事件的执行 Handler: 用来发送消息和处理消息 无论使用的post ,还是send,都会执行enqueueMessage 方法,将消息加到队列中 发送的

    2024年02月21日
    浏览(55)
  • 从源码分析Handler面试问题

    Handler 老生常谈的问题了,非常建议看一下Handler 的源码。刚入行的时候,大佬们就说 阅读源码 是进步很快的方式。 Handler 的 重要组成部分 Message 消息 MessageQueue 消息队列 Lopper 负责处理MessageQueue中的消息 对照着上面的大的逻辑图,我们深入一下,看一下,一个消息 是如何被

    2024年02月15日
    浏览(34)
  • Android Looper Handler 机制浅析

    最近想写个播放器demo,里面要用到 Looper Handler,看了很多资料都没能理解透彻,于是决定自己看看相关的源码,并在此记录心得体会,希望能够帮助到有需要的人。 本文会以 猜想 + log验证 的方式来学习 Android Looper Handler,对于一些复杂的代码会进行跳过,能够理解它们的设

    2024年02月11日
    浏览(40)
  • Android学习之路(13) Handler详解

    Handler是一套 Android 消息传递机制,主要用于线程间通信。 用最简单的话描述: handler其实就是主线程在起了一个子线程,子线程运行并生成Message,Looper获取message并传递给Handler,Handler逐个获取子线程中的Message. Binder/Socket用于进程间通信,而Handler消息机制用于同进程的线程间

    2024年02月09日
    浏览(38)
  • Handler内存泄漏原因及解决方案

    在Activity中,将Handler声明成非静态内部类或匿名内部类,这样Handle默认持有外部类Activity的引用。如果Activity在销毁时,Handler还有未执行完或者正在执行的Message,而Handler又持有Activity的引用,导致GC无法回收Activity,导致内存泄漏。如以下两种情形可能导致内存泄漏 1、在Act

    2024年02月16日
    浏览(58)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包