1. 程式人生 > >介面回撥,用最簡單的一個匿名內部類來講解(附介面回撥高階應用場景,讓你對介面的瞭解登堂入室)

介面回撥,用最簡單的一個匿名內部類來講解(附介面回撥高階應用場景,讓你對介面的瞭解登堂入室)

介面回撥,是Java開發者必須要學的一個東西,可是他呢,書上沒有,大神部落格裡也沒有,所以導致了有部分小夥紙並不瞭解這個知識,所以這裡做一個最簡單的講解。

(先不牽扯什麼非同步回撥、同步回撥)

首先,只需要記住一點,介面回撥的含義就是把程式碼換個地方寫

正常我們是這樣寫的

public class Data3 extends MyData {

    Data3() {
        System.out.print("-----");
}

可是我們因為某種原因,不得不把程式碼放到另外一個地方去寫,怎麼辦?我們第一時間想到的是,再新建一個方法,呼叫這個方法即可。

public class 
Data3 extends MyData { Data3() { cal(); } void cal() { System.out.print("-----"); }
這樣其實已經算是回調了,但是我們沒有采用介面,採用的是方法,所以稱之為方法回撥。

但是因為種種原因(原因稍後會講),我們不能總寫在我們這一個類裡吧?所以我們需要弄一個類,這裡用內部類的形式

public class Data3 extends MyData {

    Data3() {
        C c = new C();
c.cal();
}

    class 
C { void cal() { System.out.print("-----"); } }

但是總是要新建一個類,這效能開銷和程式碼量開銷也太大了吧!所以我們採用介面的形式

public class Data3 extends MyData {

    Data3() {
        call.whatToDo();
}

    Call call = new Call() {
        @Override
public void whatToDo() {
            System.out.print("-----"
); } }; interface Call { void whatToDo(); } }

定義一個內部介面,再“例項化”這個介面,再呼叫這個接口裡的方法。這就是介面回調了。

有人可能有疑問,為什麼介面可以例項化呢?其實上述程式碼,是建立了一個匿名內部類,再繼承了這個介面,效果等同於下面的程式碼:

public class Data3 extends MyData {

    Data3() {
        xxx x = new xxx();
x.whatToDo();
}
    
    interface Call {
        void whatToDo();
}
    
    class xxx implements Call {
        @Override
public void whatToDo() {
            System.out.print("-----");
}
    }
}
建立一個類,繼承這個介面,呼叫的是這個類的方法。而上面的就是通過匿名內部類的形式,其實就是Java的語法糖,讓你可以少些許多程式碼。講到這裡,看官肯定已經對介面回撥掌握通透了。

下面來分析下,為什麼需要用介面回撥,介面回撥的應用場景是怎麼樣的

onClick就是一例

mRv.setOnClickListener(new View.OnClickListener() {
    @Override
public void onClick(View v) {
        //do some thing
}
});
當你的點選事件點選了,他不會立刻執行程式碼,他會執行onClick方法,而onClick方法是交給我們來實現的。所以我們可以驗證我們的結論,介面回撥就是讓你的程式碼換一個地方執行。如果你沒有設定這個監聽器的話,那麼雖然有點選事件,但是方法肯定得不到執行。但是如果設定了監聽器的話,你所設定的接口裡的方法就會得到執行。所以我們想進行介面回撥,就必須讓呼叫者得到你這個介面。很顯然這個setOnClickListener就是一個傳遞介面的方法。

可以看一下原始碼

public void setOnClickListener(@Nullable OnClickListener l) {
    if (!isClickable()) {
        setClickable(true);
}
    getListenerInfo().mOnClickListener = l;
}
看,這裡就是把我們傳進來的介面賦值了。可想而知,最後我們執行的時候,肯定會呼叫getListenerInfo().mOnClickListener.onClick,感興趣的同學可以自行檢視原始碼。我們說了我們想進行介面回撥,就必須讓呼叫者得到你這個介面,我們之前為什麼沒有設定介面的方法呢?因為介面就是一個成員變數啊,自然可以直接呼叫。而如果你平時在用的時候,發現想要讓兩個類之間進行通訊,那麼你必須先獲取其中的那個類的例項,比如說是object,再呼叫objet.setListener(listener)即可

其實這種簡單的應用還有很多很多,下面介紹一下進階的應用。Android訊息機制

安卓的訊息機制和介面回撥有啥區別呢?其實訊息機制的基礎就是介面回撥!只不過,他把你所有的介面都進入一個佇列,可以靈活自如地控制這一系列的回撥何時執行,先後順序。上圖:


圖中的每個小方塊,都是一個介面。這裡就是訊息的靈活性了。此外他可以靈活地切換執行緒,實現執行緒間的通訊,這也是普通的介面回撥做不到的。

看似神祕的觀察者模式 

何為觀察者模式,他和介面回撥的區別簡單來說就是他是一對多的。比如有多個觀察者同時觀察著一個被觀察者,在被觀察者改變的時候,觀察者全部都觀察到了,並且做出了響應。這個過程看似高大上,其實無非也不過是利用了介面回撥。 已經精通介面回撥的你應該可以輕鬆想到是怎麼實現的了。他就是當被觀察者內容改變時,會執行被觀察 者中的某個方法,而該方法裡面呼叫的是所有觀察者介面中的方法,從而實現了一對多的觀察。

再上升一下,架構,MVP模式

MVP分V層,P層,M層。通俗來講,V是UI,P是媒婆,M是業務。P中會維護V層和M層的引用,通過分別呼叫V層和M層的介面中的方法,來實現業務和UI的分離。