序言
有需求,才會去創造。
網絡上有許多關于接口回調的文章,各有千秋,理解角度也分別不同。今天本人希望從需求角度,能讓一些對于接口回調不了解,或者概念模糊的人理解一下。本來是想寫一下回調的概念。但是我發現這樣不利于理解,所以這里我就不贅述概念了,大家看這篇博文也不要帶著固定的思維去理解,希望大家舉一反三吧。這里我從一個需求的角度讓大家理解一下回調的邏輯流程。
目的
java中接口回調隨處可見,比如說各種監聽,onClickListener,而最近比較熱的Mvp框架,其中view層抽象接口,也屬于接口回調,掌握他,你會發現,邏輯世界還是很神奇的。
應用場景
- 多線程之間數據同步問題
更具象的說法,舉個例子,我前段日子有個需求,我需要處理一些字段,但是這些字段里有一個值是北京時間,而北京時間是需要異步獲取,這樣我希望的就是獲取到北京時間后,再處理。這里我就用了接口回調。 (ps:這里我將需求盡可能的簡化,只是為了讓大家理解回調流程,詳細的需求是加密驗證,這里就不詳述了!否則有點本末倒置。)
流程示范
編寫功能模塊
功能類A
package com.dong.test;
/**
*
* @author JDD 這是一個功能類 假設他用來處理一些字段
*
*/
public class ManageFields {
String str;
/**
* 用來處理字段的方法,而其中有一個字段是北京時間,需要開啟異步線程獲取時間后再進行一些邏輯處理
*/
public void doSomething(String string) {
//這里我需要獲取北京時間,處理的話比如說拼接一段字段在北京時間前面
str = string;
//現在要獲取北京時間,這個就是開啟一個異步線程去獲取,現在問題來了怎么獲取它得到的異步時間并拼接起來的。這里就用到了回調
TimeUtil timeUtil = new TimeUtil();
timeUtil.getBjTime();
}
}
功能類B
package com.dong.test;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Date;
/**
*
* @author JDD 這個是個時間類 需要獲取北京時間
*
*/
public class TimeUtil {
/**
* 開啟異步線程去獲取時間
*/
public void getBjTime() {
new Thread(new Runnable() {
@Override
public void run() {
URL url;
try {
url = new URL("http://www.baidu.com");
URLConnection uc = url.openConnection();// 生成連接對象
uc.connect(); // 發出連接
long ld = uc.getDate(); // 取得網站日期時間
Date date = new Date(ld); // 轉換為標準時間對象
// 分別取得時間中的小時,分鐘和秒,并輸出
long bjTime = date.getTime();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // 取得資源對象
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
}
So 問題來了,該怎將獲取的時間同步給A呢?這里大家可以發散一下思維,onclick事件,觸發機制,也就是回調機制,它是完成點擊(獲取到時間后),執行回調函數 onClick(view v)(執行處理操作)。那這里我們將回調時間抽象成接口。
編寫接口
回調時間抽象成接口。
抽象接口
package com.dong.test;
/**
*
* @author JDD 時間回調接口 或者說就是監聽時間獲取
*
*/
public interface TimeListener {
//抽象方法,其中參數 就是獲取到的時間
void returnTime(long bjTime);
}```
## 改造模塊實現回調 ##
首先時間獲取模塊B中應該有一個實現了TimeListener對象的引用,這里我們去重載一下其構造函數
package com.dong.test;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.Date;
/**
- @author JDD 這個是個時間類 需要獲取北京時間
*/
public class TimeUtil {
TimeListener timeListener;
/**
* 這個是實現了TimeListener的對象的引用(其實就是ManageFileds的引用,這樣就需要ManageFields類去實現接口)
* @param timeListener
*/
public TimeUtil(TimeListener timeListener){
this.timeListener=timeListener;
}
/**
* 開啟異步線程去獲取時間
*/
public void getBjTime() {
new Thread(new Runnable() {
@Override
public void run() {
URL url;
try {
url = new URL("http://www.baidu.com");
URLConnection uc = url.openConnection();// 生成連接對象
uc.connect(); // 發出連接
long ld = uc.getDate(); // 取得網站日期時間
Date date = new Date(ld); // 轉換為標準時間對象
// 分別取得時間中的小時,分鐘和秒,并輸出
long bjTime = date.getTime();
//調用管理時間的接口
timeListener.returnTime(bjTime);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} // 取得資源對象
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
}
管理字段的類就需要實現 TimeListener接口
package com.dong.test;
/**
- @author JDD 這是一個功能類 假設他用來處理一些字段
/
public class ManageFields implements TimeListener {
String str;
/*
* 用來處理字段的方法,而其中有一個字段是北京時間,需要開啟異步線程獲取時間后再進行一些邏輯處理
*/
public void doSomething(String string) {
// 這里我需要獲取北京時間,處理的話比如說拼接一段字段在北京時間前面
str = string;
// 現在要獲取北京時間,這個就是開啟一個異步線程去獲取,并將this,也就是自己的引用傳過去
TimeUtil timeUtil = new TimeUtil(this);
timeUtil.getBjTime();
}
/**
* 這里就是當異步線程獲取到數據,調用timeListener.returnTime(bjTime)時,所回調的方法
*/
@Override
public void returnTime(long bjTime) {
// TODO Auto-generated method stub
System.out.println(str+bjTime);
}
}
## 測試代碼 ##
package com.dong.test;
public class TestCallBack {
public static void main(String[] args) {
// TODO Auto-generated method stub
ManageFields manageFields1=new ManageFields();
ManageFields manageFields2=new ManageFields();
manageFields1.doSomething("現在北京時間是:");
manageFields2.doSomething("Now BeiJingTime is:");
}
}
結果
Now BeiJingTime is:1459396779000
現在北京時間是:1459396780000
## 流程圖 ##
下面你有個大概思路了,我們看一下流程圖(viso制作)

## 拓展 ##
當然 管理字段類還可以寫成大家熟知的匿名內部類形式
package com.dong.test;
/**
- @author JDD 這是一個功能類 假設他用來處理一些字段
*/
public class ManageFields {
String str;
//匿名內部類實現
public void doSomething(String string) {
// 這里我需要獲取北京時間,處理的話比如說拼接一段字段在北京時間前面
str = string;
// 現在要獲取北京時間,這個就是開啟一個異步線程去獲取,并將this,也就是自己的引用傳過去
TimeUtil timeUtil = new TimeUtil(new TimeListener() {
@Override
public void returnTime(long bjTime) {
// TODO Auto-generated method stub
System.out.println(str+bjTime);
}
});
timeUtil.getBjTime();
}
}
## 后話 ##
當然,你要是了解Rxjava,或者觀察者模式,抑或handler等,都是可以實現這種需求的,但是,總有一種場景,有一種工具更配的來。就跟工具箱里的扳手一樣,你有很多扳手,但是也有不同的螺絲,匹配的來的工具不是更給力么!
然而回調有時候不是必須的,因為有一個問題就是callbackhell-回調地獄,我的認知就是由于各種回調嵌套,導致工程可讀性,可塑性差。所以大家也要兩面性的看待問題!
## 源碼 ##
[接口回調樣例源碼](http://7xsffo.com1.z0.glb.clouddn.com/TestCallBack.rar "接口回調樣例源碼")