一、為什么會(huì)有接口回調(diào)?什么是接口回調(diào)?
其實(shí)這兩個(gè)問題是一個(gè)問題,知道了接口回調(diào)的原理自然就知道了為什么會(huì)有這么個(gè)東西。我們知道java中接口是不可以直接創(chuàng)建實(shí)例的,那么問題來了,假如我把一個(gè)接口聲明為一個(gè)變量,那么我執(zhí)行這個(gè)接口中的方法,接口沒有實(shí)例它該怎么辦呢?啊哈,這里自然又改出現(xiàn)java中的另一個(gè)特性---“多態(tài)”,這時(shí)java虛擬機(jī)自然會(huì)去找其子類,調(diào)用其子類中已經(jīng)重載的該方法,這里就是接口回調(diào)的本質(zhì)!!我們只需要給該變量指向其子類的地址就可以在調(diào)用的時(shí)候知道調(diào)用子類的方法。那么我們就可以在A類中創(chuàng)建接口的子類實(shí)例,在B類中創(chuàng)建一個(gè)接口的變量,把A類的地址傳給B類的變量,在變量執(zhí)行接口中的方法的時(shí)候就會(huì)調(diào)用A類中重寫的方法,這就是接口回調(diào)的執(zhí)行步驟。我們?cè)诰W(wǎng)絡(luò)請(qǐng)求等耗時(shí)的操作的時(shí)候會(huì)使用到該機(jī)制,用來把得到的數(shù)據(jù)傳回主線程中。
二、使用實(shí)例
下面我們就來用一個(gè)網(wǎng)絡(luò)請(qǐng)求的實(shí)例來演示如何使用該機(jī)制,為了盡量的減少代碼,使主要代碼能夠突出,里面的一些不必要的容錯(cuò)代碼就沒有寫了,大家在正式的項(xiàng)目中希望可以做好容錯(cuò)處理。
我們用一個(gè)按鈕和一個(gè)imageView來演示,當(dāng)點(diǎn)擊按鈕的時(shí)候去下載數(shù)據(jù),在數(shù)據(jù)下載完成之后使用接口回調(diào)把數(shù)據(jù)傳回來顯示在imageview中。效果如下:
布局文件很簡(jiǎn)單就不在貼出來了,我們有3個(gè)類,一個(gè)是回調(diào)的接口,一個(gè)是主activity,一個(gè)為執(zhí)行下載并且把數(shù)據(jù)回調(diào)回來的Callee類,下面來看接口類:
import android.graphics.Bitmap;
/**
* Created by JimLv on 2016/5/31.
*/
public interface CallBackInterface {
void result(Bitmap bm);
}
定義了一個(gè)用于傳遞數(shù)據(jù)的方法,來看看Callee類:
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* Created by JimLv on 2016/5/31.
*/
public class Callee {
private final String IMGURL = "http://f.hiphotos.baidu.com/zhidao/pic/item/b21bb051f8198618a323ac464bed2e738ad4e688.jpg";
//持有接口變量
CallBackInterface mInterface;
Callee(CallBackInterface theInterface) {
//這里是關(guān)鍵,把外部的接口實(shí)例引用到該類,給變量賦值
mInterface = theInterface;
//創(chuàng)建對(duì)象的時(shí)候執(zhí)行下載
executeDown();
}
public void executeDown() {
new Thread(new Runnable() {
@Override
public void run() {
try {
HttpURLConnection conn = (HttpURLConnection) new URL(IMGURL).openConnection();
conn.setConnectTimeout(5 * 1000);
conn.setRequestMethod("GET");
mInterface.result(BitmapFactory.decodeStream(conn.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
在這里我們聲明了一個(gè)接口變量,在類的初始化方法中把接口的子類的地址賦給該變量并且調(diào)用下載數(shù)據(jù)的方法,在數(shù)據(jù)下載完成之后調(diào)用接口變量的方法把數(shù)據(jù)傳給該方法,執(zhí)行該方法實(shí)際是執(zhí)行子類的該方法,這就是接口回調(diào)真正做的事。
最后我們來看MainActivity類:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private ImageView imgv;
private Button downImgBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imgv = (ImageView) findViewById(R.id.imgv);
downImgBtn = (Button) findViewById(R.id.downImgBtn);
//點(diǎn)擊按鈕去下載
downImgBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
//從接口回調(diào)得到數(shù)據(jù),因?yàn)橄螺d是在子線程中,所以這里要變到主線程中設(shè)置圖片
new Callee(new CallBackInterface() {
@Override
public void result(final Bitmap bm) {
runOnUiThread(new Runnable() {
@Override
public void run() {
imgv.setImageBitmap(bm);
}
});
}
});
}
}
在這里我們用匿名內(nèi)部類創(chuàng)建該接口的子類實(shí)例,子類重載的方法中因?yàn)槭沁\(yùn)行在子線程中的,我們無法操作UI,所有調(diào)用了runOnUiThread方法,把數(shù)據(jù)更新到imageview中,整個(gè)的demo就這么點(diǎn)是不是很簡(jiǎn)單呢?
掃描關(guān)注我的微信公眾號(hào):
三、總結(jié)
哈哈,整個(gè)回調(diào)機(jī)制是不是很簡(jiǎn)單呢?其實(shí)以前不懂這個(gè)的時(shí)候也是很頭疼,理不清里面的邏輯,百度上面的文章又是一大堆,可是里面內(nèi)容啰啰嗦嗦不知所云,真是肯爹不淺啊?!啊痹撍赖某绦蚬贰啊眫~~~~~~~~~好啦,其實(shí)我也很討厭別人這么說,不過無所謂啦,我們是有上進(jìn)心的工程師,不是和你家那位一樣的程序狗!弄懂了一個(gè)技術(shù)的本質(zhì)是什么之后使用起來才不會(huì)無從下手,遇到問題才會(huì)知道如何解決。如果你覺得這篇文章寫的還不錯(cuò)希望你點(diǎn)個(gè)贊,如果想看我以后寫的文章請(qǐng)關(guān)注我,祝步步高升,天天開心!
最后附上demo:點(diǎn)擊打開鏈接