1. 程式人生 > >Android-Handler機制詳解並自定義Handler

Android-Handler機制詳解並自定義Handler

之前研究過Android的Handler機制,但是一直沒有機會自己實現一次。最近又看到這個Handler機制,於是決定自己實現以下這個Handler機制。
首先,簡單介紹以下Handler機制。

Handler機制在Android中通常用來更新UI:子執行緒執行任務,任務執行完畢後傳送訊息:Handler.sendMessage(),然後在UI執行緒Handler.handleMessage()就會呼叫,執行相應處理。

Handler機制有幾個非常重要的類:

Handler:用來發送訊息:sendMessage等多個方法,並實現handleMessage()方法處理回撥(還可以使用Message或Handler的Callback進行回撥處理,具體可以看看原始碼)。

Message:訊息實體,傳送的訊息即為Message型別。

MessageQueue:訊息佇列,用於儲存訊息。傳送訊息時,訊息入佇列,然後Looper會從這個MessageQueen取出訊息進行處理。

Looper:與執行緒繫結,不僅僅侷限於主執行緒,繫結的執行緒用來處理訊息。loop()方法是一個死迴圈,一直從MessageQueen裡取出訊息進行處理。

原理圖如下:
這裡寫圖片描述

按照上面介紹的4個重要組成類,從內向外依次自定義相應的類,實現Handler機制。
MyMessage類

public class MyMessage {
    private int code;
    private
String msg; MyHandler target; public MyMessage(int code, String msg) { this.code = code; this.msg = msg; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } public String getMsg() { return
msg; } public void setMsg(String msg) { this.msg = msg; } }

MessageQueue類:(由於該類可以有多種實現方式,所以在此定義一個介面)

public interface IMyMessageQueue {
    MyMessage next() throws InterruptedException;
    void enqueueMsg(MyMessage msg) throws InterruptedException;
}

從Android原始碼中瞭解到,這個MessageQueue是一個佇列,所以在此簡單的已一個BlockingQueue佇列來實現訊息的進隊出隊操作:

public class MyBlockingQueue implements IMyMessageQueue {
    private BlockingQueue<MyMessage> mQueue;

    public MyBlockingQueue(int init) {
        this.mQueue = new LinkedBlockingDeque<>(init);
    }

    @Override
    public MyMessage next() throws InterruptedException {
        return mQueue.take();
    }

    @Override
    public void enqueueMsg(MyMessage msg) throws InterruptedException {
        mQueue.put(msg);
    }
}

MyLooper類:持有一個MyMessageQueue例項,並使用ThreadLocal綁定當前執行緒,啟動一個死迴圈。

public class MyLooper {
    private static final ThreadLocal<MyLooper> THREAD_LOCAL = new ThreadLocal<>();
    IMyMessageQueue mMessageQueue;
    private static MyLooper mMainLooper;

    public MyLooper() {
        mMessageQueue = new MyBlockingQueue(4);
    }

    public static void prepare() {
        if (null != THREAD_LOCAL.get()) {
            throw new RuntimeException("Only one looper can be created per thread.");
        }
        THREAD_LOCAL.set(new MyLooper());
    }

    public static void prepareMainLooper() {
        prepare();
        synchronized (MyLooper.class) {
            if (null != mMainLooper) {
                throw new RuntimeException("MainLooper has already been prepared.");
            }
            mMainLooper = myLooper();
        }
    }

    public static void loop() {
        final MyLooper looper = myLooper();
        if (null == looper) {
            throw new RuntimeException("No looper! MyLooper.prepare() wasn't called on this thread.");
        }
        for (; ; ) {
            MyMessage msg = null;
            try {
                msg = looper.mMessageQueue.next();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (null != msg) {
                msg.target.handleMessage(msg);
            }
        }
    }

    public static MyLooper getMainLooper() {
        return mMainLooper;
    }

    public static MyLooper myLooper() {
        return THREAD_LOCAL.get();
    }
}

MyHandler類:持久訊息佇列,並定義一個抽象方法,負責傳送和處理訊息。

public abstract class MyHandler {
    private IMyMessageQueue mQueue;

    public MyHandler(MyLooper looper) {
        mQueue = looper.mMessageQueue;
    }

    public MyHandler() {
        MyLooper.myLooper();
    }

    public void sendMessage(MyMessage msg) {
        msg.target = this;
        try {
            mQueue.enqueueMsg(msg);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public abstract void handleMessage(MyMessage msg);
}

到此,自定義Handler功能程式碼實現,下面測試一下啟動MyMainLooper,並在子執行緒中使用MyHandler傳送和處理訊息。

TestMyHandler

public class TestMyHandler {

    @Test
    public void test() {
        MainThread mainThread = new MainThread();
        mainThread.start();

        while (null == MyLooper.getMainLooper()) {
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        MyHandler handler = new MyHandler(MyLooper.getMainLooper()) {
            @Override
            public void handleMessage(MyMessage msg) {
                switch (msg.getCode()) {
                    case 1:
                        System.out.print(msg.getMsg() + "在" + Thread.currentThread().getName() + "上執行!\r\n");
                        break;
                    case 2:
                        System.out.print(msg.getMsg() + "在" + Thread.currentThread().getName() + "上執行!\r\n");
                        break;
                }
            }
        };

        new Thread(() -> {
            MyMessage myMessage = new MyMessage(1, "子執行緒訊息1");
            handler.sendMessage(myMessage);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            MyMessage myMessage2 = new MyMessage(2, "子執行緒訊息2");
            handler.sendMessage(myMessage2);
        }).run();
    }

    /**
     * 主執行緒
     */
    public class MainThread extends Thread {
        public MainThread() {
            setName("MainThread");
        }

        @Override
        public void run() {
            MyLooper.prepareMainLooper();
            System.out.print(getName() + "has been prepared.\r\n");
            MyLooper.loop();
        }
    }
}

測試結果
這裡寫圖片描述