一谢床、為什么會有接口回調(diào)?什么是接口回調(diào)厘线?
其實這兩個問題是一個問題萤悴,知道了接口回調(diào)的原理自然就知道了為什么會有這么個東西。我們知道java中接口是不可以直接創(chuàng)建實例的皆的,那么問題來了,假如我把一個接口聲明為一個變量蹋盆,那么我執(zhí)行這個接口中的方法费薄,接口沒有實例它該怎么辦呢?啊哈栖雾,這里自然又改出現(xiàn)java中的另一個特性---“多態(tài)”楞抡,這時java虛擬機自然會去找其子類,調(diào)用其子類中已經(jīng)重載的該方法析藕,這里就是接口回調(diào)的本質(zhì)U偻ⅰ!我們只需要給該變量指向其子類的地址就可以在調(diào)用的時候知道調(diào)用子類的方法账胧。那么我們就可以在A類中創(chuàng)建接口的子類實例竞慢,在B類中創(chuàng)建一個接口的變量,把A類的地址傳給B類的變量治泥,在變量執(zhí)行接口中的方法的時候就會調(diào)用A類中重寫的方法筹煮,這就是接口回調(diào)的執(zhí)行步驟。我們在網(wǎng)絡(luò)請求等耗時的操作的時候會使用到該機制居夹,用來把得到的數(shù)據(jù)傳回主線程中败潦。
二本冲、使用實例
下面我們就來用一個網(wǎng)絡(luò)請求的實例來演示如何使用該機制,為了盡量的減少代碼劫扒,使主要代碼能夠突出檬洞,里面的一些不必要的容錯代碼就沒有寫了,大家在正式的項目中希望可以做好容錯處理沟饥。
我們用一個按鈕和一個imageView來演示添怔,當(dāng)點擊按鈕的時候去下載數(shù)據(jù),在數(shù)據(jù)下載完成之后使用接口回調(diào)把數(shù)據(jù)傳回來顯示在imageview中闷板。效果如下:
布局文件很簡單就不在貼出來了澎灸,我們有3個類,一個是回調(diào)的接口遮晚,一個是主activity性昭,一個為執(zhí)行下載并且把數(shù)據(jù)回調(diào)回來的Callee類,下面來看接口類:
import android.graphics.Bitmap;
/**
* Created by JimLv on 2016/5/31.
*/
public interface CallBackInterface {
void result(Bitmap bm);
}
定義了一個用于傳遞數(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)鍵糜颠,把外部的接口實例引用到該類,給變量賦值
mInterface = theInterface;
//創(chuàng)建對象的時候執(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();
}
}
在這里我們聲明了一個接口變量萧求,在類的初始化方法中把接口的子類的地址賦給該變量并且調(diào)用下載數(shù)據(jù)的方法其兴,在數(shù)據(jù)下載完成之后調(diào)用接口變量的方法把數(shù)據(jù)傳給該方法,執(zhí)行該方法實際是執(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);
//點擊按鈕去下載
downImgBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
//從接口回調(diào)得到數(shù)據(jù),因為下載是在子線程中匀归,所以這里要變到主線程中設(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)建該接口的子類實例穆端,子類重載的方法中因為是運行在子線程中的体啰,我們無法操作UI荒勇,所有調(diào)用了runOnUiThread方法枕屉,把數(shù)據(jù)更新到imageview中鲤氢,整個的demo就這么點是不是很簡單呢?
掃描關(guān)注我的微信公眾號:
三、總結(jié)
哈哈威恼,整個回調(diào)機制是不是很簡單呢箫措?其實以前不懂這個的時候也是很頭疼斤蔓,理不清里面的邏輯弦牡,百度上面的文章又是一大堆驾锰,可是里面內(nèi)容啰啰嗦嗦不知所云椭豫,真是肯爹不淺啊〈以撸“”該死的程序狗“”~~~~~~~~~~好啦,其實我也很討厭別人這么說姓言,不過無所謂啦何荚,我們是有上進心的工程師餐塘,不是和你家那位一樣的程序狗戒傻!弄懂了一個技術(shù)的本質(zhì)是什么之后使用起來才不會無從下手需纳,遇到問題才會知道如何解決。如果你覺得這篇文章寫的還不錯希望你點個贊兵扬,如果想看我以后寫的文章請關(guān)注我器钟,祝步步高升傲霸,天天開心灭必!
最后附上demo:點擊打開鏈接