Android 비동기 메시지 처리 메커니즘 Handler

7815 단어
쉽게 말 하면 스 레 드 에서 무한 순환 을 열 어 대기 열 에 있 는 메 시 지 를 처리 하 는 것 입 니 다.
    @Override
    public void run() {
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
        }
        Looper.loop();
    }

설명: 데이터 구조 대기 열: 단일 체인 표.다음 소스 코드 에서 보 듯 이 하나의 링크 입 니 다.
MessageQueue.java
{    
    boolean enqueueMessage(Message msg, long when) {       
       Message p = mMessages;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }
    }
}

문제 1: 무한 순환?그럼 이상 한 걸 던 질 까요?맞 아, 해결 방법 은 소식 이 없 을 때 막 는 거 야.
문제 2: 어떻게 막 습 니까?
문제 3: 또 어떻게 스 레 드 를 깨 웠 습 니까?
무한 순환 추적
어 셈 블 리 언어 가 무한 순환 을 실현 하 다.
fin:
HLT

JMP fin

C 언어 무한 순환 실현
fin:
/**    HLT,  C      HLT*/

goto fin;    //        

Android Java 무한 순환 실현

for( ; ; ) {



}

1. 스 레 드 중 무한 순환 오픈
Looper.java

Looper.java
{
    public static void loop() {
        for(;;){
            Message msg = queue.next();//     
            if (msg == null) {
                return;//    ,loop()      main    。
            }
        }

    }
}

2. 대기 열 에 있 는 Message 대상 가 져 오기
MessageQueue.java
{

    synchronized (this) {
        //Try to retrieve the next message.  Return if found.(         ,      )
        Message next() {
            //Handler target
            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());//
        }
    }
}

Message.java
{
    int flags;
    //<

2.1. Message 대상 을 처리 하 는 시간 판단
MessageQueue.java
{
    Message next() {
        final long now = SystemClock.uptimeMillis();
        synchronized(this) {
            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);                   
                }
            }
        }  
    }
}

Message.java
{
    long when;
    Handler target;
    public Message() {    }

    /***/
    void recycleUnchecked() {
       when = 0;
    }
    /**  */
    public void recycle() {
        recycleUnchecked();
    }

    
    public long getWhen() {
        return when;
    }


}

2.2. Message Queue 는 Message 대기 열 을 어떻게 구성 합 니까?
Message.java
{   //        Message  
    Message next;

    private static Message sPool;

    private static int sPoolSize = 0;

    private static final int MAX_POOL_SIZE = 50;

    /**
     *              。         ,       。
     */
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

    //<6>
    public void recycle() {
        if (isInUse()) {
            if (gCheckRecycle) {
                throw new IllegalStateException("This message cannot be recycled because it "
                        + "is still in use.");
            }
            return;
        }
        recycleUnchecked();
    }

    //<7>
    void recycleUnchecked() {
        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }
}

MessageQueue.java
{
    /**
     *
     *
     *<5>              !  !  !
     *
     */
    boolean enqueueMessage(Message msg, long when) {
        //  ,      
        synchronized (this) {
            if (mQuitting) {
                msg.recycle();
            }

        }
    }
}

Handler.java
{
    //<1>
    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }

    //<2>
    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

    //<3>
    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);
    }

    //<4>
    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }
}

3. 스 레 드 차단
MessageQueue.java
MessageQueue.java
{
    Message next() {
        for(;;) {
            //      ,             ,        
            //    :           。
            Binder.flushPendingCommands()
            //           ,      --      ,     ?
            nativePollOnce(ptr, nextPollTimeoutMillis);
        }
    }
}

현지 방법 을 사용 하 는 것 을 보 니 궁지 에 몰 린 듯 한 윙윙 거 리 는 느낌 이 들 지 않 습 니까?사실은 위 에서 설명 한 c 언어 무한 순환 코드 를 보면 라 이브 러 리 에서 이렇게 이 루어 진 것 임 을 대체적으로 알 수 있다.
대기 열 에 Message 대상 이 있 지만 이 대상 을 처리 할 시간 이 되 지 않 아 차단 시간 을 계산 합 니 다.
MessageQueue.java
{
    Message next() {
        for(;;) {
            //nextPollTimeoutMillis    
            nativePollOnce(ptr, nextPollTimeoutMillis);
            if (msg != null) {
                if (now < msg.when) {
                    //         
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                }
            }
        }
    }
}

대기 열 에 Message 대상 이 없 으 면 Message 대상 이 대기 열 에 삽입 되 었 을 때 스 레 드 를 깨 울 때 까지 무기한 차단 합 니 다.
MessageQueue.java
{
    Message next() {
        for(;;) {
            //nextPollTimeoutMillis    
            nativePollOnce(ptr, nextPollTimeoutMillis);
            synchronized (this) {
            Message msg = mMessages;
            if (msg != null && msg.target == null) {
            
            }
            if (msg != null) {
            
            } else {
                // No more messages.
                //-1        
                nextPollTimeoutMillis = -1;  
            }
        }
    }

    boolean enqueueMessage(Message msg, long when) {
        synchronized (this) {
            boolean needWake;
            if (needWake) {
                //    
                nativeWake(mPtr);
            }
           

        }
    }

}

Message 대상 의 코드 를 가 져 와 서 잘 썼 습 니 다. 읽 고 공부 할 수 있 습 니 다.

좋은 웹페이지 즐겨찾기