如何寫一個Listener之一

如何寫一個Listener之一

假設現在你有兩個類別, 分別是A類別跟B類別,

A類別有一個很久的任務在執行, 
B類別則是必須等A類別執行完畢以後, 再執行自己的任務

這時候有幾種方法可以解決這樣的情況:

  • B不斷的去問A做完了嗎?
  • 把B排在A的後面直到A做完
  • 當A做完了透過機制告訴B已經做完了, 可以來拿結果了

今天要解釋的就是第三種情況。
假設今天有一個類別A

public class A {
    private B b;
    public A(B b) {
        this.b = b;
    }

    public void handleLongTask(){
        try {
            System.out.println("A task is running.");
            Thread.sleep(1000);
            b.handleEvent("ok");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

它執行一個很長時間的任務。
然後有一個類別B, 必須等待A執行完畢, 才可以執行B要執行的任務。

public class B {
    public void handleEvent(String result){
        int i = 0;
        if(result.equals("ok")){
            System.out.println("A task is finished.");
        }
        //B自己的任務
        while(i < 100){
            i++;
        }
        System.out.println("B task is finished");
    }
}

在main方法內

public static void main(String[] args) {
    B b = new B();
    A a = new A(b);
    a.handleLongTask();
}

會看到輸出結果是

A task is running.
A task is finished.
B task is finished

但是這樣其實很沒有效率的,
如果能夠在A執行的時候, B持續進行它跟A無關的任務, 那該有多好?
其實這是辦得到的,
只需要透過Listener就可以簡單完成這樣的功能,
首先我們先在A建立一個interface。

public interface OnCompletedListener{
    void onCompleted(String result);
}
private OnCompletedListener mOnCompletedListener;
public void setOnCompletedListener(OnCompletedListener listener){
    mOnCompletedListener = listener;
}

接著在A的長任務內執行

public void handleLongTask(){
    try {
        System.out.println("A task is running.");
        Thread.sleep(1000);
        if(mOnCompletedListener != null){
            mOnCompletedListener.onCompleted("ok");
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

B的類別改成這樣

public class B {
    private A a;

    public B(A a) {
        this.a = a;
        a.setOnCompletedListener(new A.OnCompletedListener() {
            @Override
            public void onCompleted(String result) {
                if(result.equals("ok")){
                    System.out.println("A task is finished.");
                }
            }
        });
    }

    public void handleEvent(){
        int i = 0;
        while(i < 100){
            i++;
        }
        System.out.println("B task is finished");
    }
}

而我們的main方法改成

public static void main(String[] args) {
    public static void main(String[] args) {
        A a = new A();
        final B b = new B(a);
        //A的任務
        Executors.newSingleThreadExecutor().submit(new Runnable() {
            @Override
            public void run() {
                a.handleLongTask();
            }
        });
        //B的任務
        Executors.newSingleThreadExecutor().submit(new Runnable() {
            @Override
            public void run() {
                b.handleEvent();
            }
        });
    }
}

透過兩條獨立的Thread來分別執行A與B的任務,
可以看出A跟B的任務都獨立開來了,
只要A執行完畢透過Listener來通知B執行結束,
這麼一來B即使在執行自己的任務, 也不會因為等待A而停滯。
結果如下

A task is running.
B task is finished
A task is finished.

github