보기 처리기 메시지 메커니즘의 관점에서 소스 코드의 분석

사실, 인터넷은 아주 좋은 잘 쓰여진 글을 많이 가지고,이 뇌졸중 분명 생각이다 쓰고, 기억을 강화하고 싶었다.

여기에 훌륭한 기사를 추천합니다 :

https://blog.csdn.net/zip_tts/article/details/86097136#commentBox

메시지 핸들러 메커니즘은 주로 다섯 개 가지 구성 요소, 핸들러, 자벌레, 메시지, MessageQueue가,의 ThreadLocal을 가지고

  • 메시지 핸들러로 메시지를 처리하고 메시지를 보내기위한 처리 센터입니다.
  • 메일 메시지를 취득하는 전력 메시지로서 루퍼.
  • 메시지를 운반 캐리어와 같은 메시지 메시지.
  • 메시지를 저장하는 메시지 대기열로 MessageQueue가.
  • ThreadLocal를 내부 스레드 클래스 데이터를 저장하고, 데이터는 지정된 thread 얻을 수있다.
    **

첫째, 메시지 것입니다

무엇보다도, 메시지 전송이 내부에 무엇 무엇을 우리가 원하는 이해합니다.

public final class Message implements Parcelable {
	public int what;
    public int arg1;
    public int arg2;
    public Object obj;
    public Messenger replyTo;
    int flags;
    long when;
    Bundle data;
    Handler target;
    }

당신은 아주 익숙한 느낌이되지 않습니다? 우리는 필요가 사용되는 방법을 많이 씁니다.
여기에 대상이고, 핸들러는 우리가 나중에 이해하는 데 도움이 메시지 핸들러의 메시지를 저장하는 것입니다의 유형입니다.

두, 핸들러 및 전송 인스턴스화

핸들러 일곱 생성자의 예

public Handler() {
    this(null, false);
}

public Handler(Callback callback) {
    this(callback, false);
}

public Handler(Looper looper) {
    this(looper, null, false);
}

public Handler(Looper looper, Callback callback) {
    this(looper, callback, false);
}
   
public Handler(boolean async) {
    this(null, async);
}

public Handler(Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
        final Class<? extends Handler> 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());
        }
    }
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread " + Thread.currentThread()
                    + " that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

우리는 지정되지 않은 경우 스레드 루퍼 루퍼는 처리기를 인스턴스화하는 데 사용되는 코드에서 볼 수 있습니다.
사실, 핸들러를 보내는 소개가 많은 방법이 있습니다,하지만 모양은 마지막 방법을 지시하는 enqueueMessage 찾을 수 있습니다, 메시지 메시지 캡슐화 된 후 발송.

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

상기 코드 자체에 대상 점의 메시지는 상기에 송신 MessageQueue가, 음) (이하이 MessageQueue가 enququqMessage 분석 이해

三, MessageQueue가

부울 enqueueMessage (메시지 MSG, 긴 경우) {
경우 (msg.target == NULL) {
( "메시지가 대상이 있어야합니다.") 새, IllegalArgumentException를 throw;
}
경우 (msg.isInUse ()) {
( "이 메시지는 이미 사용 중입니다."MSG +) 새로운 IllegalStateException을 발생;
}

    synchronized (this) {
        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.
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            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;
        }

        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

사실, 메시지 큐, 지연이 순차적으로 설정되어 있지 않은 경우, 링크 된 목록에 저장된 시간에 메시지가, 시간이 분류 것이다.

네, 루퍼

다음은 루퍼 생성자입니다 :

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

그런 다음 그것을 확실히 당신이 얻을 수있는 다른 방법이 될 것입니다, 즉, 루퍼는 객체를 생성하는 새로운 방법으로하지 않습니다 그것의 생성자는 개인 것을 볼 수 있습니다. 방법을 준비,이 prepareMainLooper 그 안에있는 소스 코드를 볼 계속,

public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

루퍼 prepareMainLooper 주로 항상 주 스레드 자벌레가 있기 때문에, 정상적인 상황에서, 금지, 메인 쓰레드를 생성하는 데 사용됩니다. 그리고 당신은 () 만들거나 준비하는 주요 방법을 볼 수 있습니다.

 private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

그 곳의 ThreadLocal입니다

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

분명히, 이것은 스레드 루퍼의 출력을 생성하고, ThreadLocal을 유지 할 수 있습니다.
그래서 지금 루퍼는 사용이 메시지 MessageQueue가로 보낼 방법을 만들었습니다? 그의 루프 ()

 public static void loop() {
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    final MessageQueue queue = me.mQueue;
    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }

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


        try {
            msg.target.dispatchMessage(msg);
            end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
    }

나는 거의 핵심 코드 위에, 몇 가지 코드를 삭제. MessageQueue가 본질적으로 하나의리스트에, 루프는 그것을 직접 비우 돌아가거나 경우 메시지 MessageQueue가 옆 통과 정지, 무한 루프입니다 (;;)에 사용되는 msg.target.dispatchMessage(msg)핸들러 msg.target에 정보를 전송 dispatchMessage의 이동으로 입력합니다.

다섯, 핸들러 수집 및 처리

그런 다음 코드는 dispatchMessage의 핸들러에 온 ()에서

 public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

여기에 몇 가지 판단 문이다. 핸들러에서,이 방법은의 메시지를 처리하는 것입니다, 인터페이스 콜백이 한 방향으로 만의 handleMessage이 선언 콜백 생성자에 전달. 방법이 있는지 생성자에서 들어오는 콜백이 핸들러는 또한 handleMessage 메소드를 정의하지 않는 경우는 물론, 기본값은 빈 구현입니다. 이것은 메시지 오버라이드이 방법에 의해 처리 될 수있다.
그래서이 모든 과정이 끝났다.

게시 57 개 원래 기사 · 원의 찬양 3 · 조회수 6220

추천

출처blog.csdn.net/qq_39830579/article/details/88738717