handler 원본 분석

6670 단어

handler 메커니즘


간단하게 요약하면handler 메커니즘은 크로스 라인 이전의 통신 방식을 제공했다.먼저 간단한 코드 예시를 보십시오. 루틴 A는handler 대상을 만들고 looper를 호출합니다.prepare (), Looper 대상을 만들고 MessageQueue를 만들고 현재 라인에 연결합니다.그리고 looper 퀴즈를 시작합니다.sendMessage Delayed () 는 Message를 MessageQueue에 추가합니다. 그리고 라인 B는 Message를 처리하여handler를 만드는 라인에 메시지를 보낼 수 있습니다. 최종적으로 그handlerMessage를 보냅니다.
class LoopThread extends Thread {
        public Handler mHandler = null;

        public LoopThread(String threadName) {
            super(threadName);
        }

        @Override
        public void run() {
            Looper.prepare();
            mHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    switch (msg.what) {
                        case RESPONSE:
                            System.out.println(" [" + Thread.currentThread().getName() + "] ");
                            break;
                        default:
                            break;
                    }
                }
            };
            Looper.loop();
        }
    }

    //threadB 
    final LoopThread threadB = new LoopThread("ThreadB");
    threadB.start();


    //threadA 
    Thread threadA = new Thread(new Runnable() {
        @Override
        public void run() {
            Message msg = new Message();
            msg.what = RESPONSE;
            threadB.mHandler.sendMessage(msg);
            System.out.println("["+Thread.currentThread().getName() + "] ");
        }
    }, "ThreadA");

    threadA.start();


다음에handler의 원본 코드를 분석하고 쓸모없는 방법을 생략하고 주요한 방법을 설명함으로써handler의 메커니즘을 이해한다.

handler sendMessage () 메시지 대기열에 메시지 추가

//handler.post()
// sendMessageDelayed,  enqueueMessage
public final boolean post(Runnable r)
{
   return  sendMessageDelayed(getPostMessage(r), 0);
}

//Message.obtain()  Message  ,  Runnable  Message callback
private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

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


looper 순환 처리 메시지 대기열


주 루틴은 기본적으로 다음과 같은 두 가지 방법을 사용합니다.하위 라인에서handler를 사용하면 이 두 가지 방법을 앞뒤로 추가해야 합니다. 그러면 하위 라인에서MeesageQueue를 돌아가며 조회할 수 있습니다.

looper.prepare()


Looper 객체 만들기, MessageQueue 만들기, Looper는 MessageQueue 참조, 현재 스레드는 Looper 객체 참조
// looper ,  ThreadLocal
private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    // new  Looper 
    sThreadLocal.set(new Looper(quitAllowed));
}

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

looper.loop()


MeesageQueue를 옮겨다니며handler의 dispatchMessage () 를 호출하여 Message를 처리합니다
// meesageQueue
public static void loop() {
    // ThreadLocal Looper 
    final Looper me = myLooper();
    
    // Looper MeesageQueue
    final MessageQueue queue = me.mQueue;

    // 
    for (;;) {
        // ,  
        Message msg = queue.next(); // might block
        if (msg == null) {
            return;
        }

        // Message handler dispatchMessage() 
        msg.target.dispatchMessage(msg);
      
    }
}

handler 처리 메시지


여기에 msg에 콜백이 있다면 msg의 콜백을 먼저 실행합니다.그렇지 않으면handler의callback의handleMessage를 실행합니다.그렇지 않으면handler 하위 클래스의handleMessage를 실행합니다.
public void dispatchMessage(Message msg) {
    // Message ,  callback
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        // Message
        handleMessage(msg);
    }
}

private static void handleCallback(Message message) {
    message.callback.run();
}

//handlerMessage ,  
public void handleMessage(Message msg) {
}

기본 스레드에는 기본적으로 ActivityThread의 Looper 객체가 있습니다.
public static void main(String[] args) {
    Looper.prepareMainLooper();

    ActivityThread thread = new ActivityThread();
    thread.attach(false);

    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }

    AsyncTask.init();

    if (false) {
        Looper.myLooper().setMessageLogging(new
                LogPrinter(Log.DEBUG, "ActivityThread"));
    }

    Looper.loop();
}

handler 구조 방법
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();
    // handler  looper.prepare(),  。 ?
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

HandlerThread


주요 역할은 로퍼가 있는 라인을 간단하게 만들고handler의 메커니즘을 사용하여 비동기 처리를 편리하게 하는 것이다.그러나 그는 단지 하나의 라인만 있어서 직렬 임무에 적합하고 병렬 임무를 수행하기에 적합하지 않다.예를 들어 네트워크 IO가 막히는 시간이 비교적 길면 스레드 탱크나 asyncTask+스레드 탱크를 사용해서 처리하는 것을 추천합니다.소스:
public class HandlerThread extends Thread {
    public HandlerThread(String name, int priority) {
        super(name);
        // , , 
        mPriority = priority;
    }
    
    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

예:
HandlerThread workerThread = new HandlerThread("workerThread", Process.THREAD_PRIORITY_BACKGROUND);
    workerThread.start();
    mHandler = new Handler(workerThread.getLooper());

좋은 웹페이지 즐겨찾기