關(guān)于網(wǎng)絡(luò)封裝

在同一個app里面,我們可能會在很多地方都使用到網(wǎng)絡(luò)請求,而發(fā)送網(wǎng)絡(luò)請求的代碼基本上都是相同的。
所以,在通常情況下,我們應(yīng)該將這些通用的網(wǎng)絡(luò)操作提取到一個公共的類里面,并提供一個靜態(tài)方法,當(dāng)想要發(fā)起網(wǎng)絡(luò)請求的時候只需要簡單的調(diào)用一下這個方法即可,比如:

public class HttpUtil {
    public static String sendHttpRequest(String address) {
        HttpURLConnection connection = null;
        try {
            URL url = new URL(address);
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(8000);
            connection.setReadTimeout(8000);
            connection.setDoInput(true);
            connection.setDoOutput(true);
            InputStream is = connection.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            return response.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return e.getMessage();
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }
}

這樣,以后每次需要發(fā)送一條Http請求的時候就可以直接寫:

String address = "http://www.google.com";
String response = HttpUtil.sendHttpRequest(address);

但是,這里有一個問題。網(wǎng)絡(luò)請求通常都是屬于耗時操作,而我們在sendHttpRequest()方法中并沒有開啟線程,這樣就很有可能導(dǎo)致在調(diào)用sendHttpRequest()方法的時候使得主線程被阻塞。

那么,這個問題該如何解決呢?
我們是不是直接在sendHttpRequest()方法內(nèi)部開啟一個線程就ok了呢?

答案當(dāng)然是否定的。
因?yàn)椋绻覀冊?code>sendHttpRequest()方法中開啟了一個線程來發(fā)起Http請求,那么服務(wù)器響應(yīng)的數(shù)據(jù)是無法進(jìn)行返回的,所有的耗時邏輯都是在子線程進(jìn)行的,sendHttpRequest()方法會在服務(wù)器還沒來得及響應(yīng)的時候就執(zhí)行結(jié)束了,當(dāng)然也就無法返回響應(yīng)的數(shù)據(jù)了。
(思考 為什么?)

實(shí)際上,我們需要使用Java的回調(diào)機(jī)制來解決這個問題。
首先我們定義一個接口,

public interface HttpCallbackInterface {
    
    void onSucceed(String response);
    
    void onFail(Exception e);
    
}

我們在接口中定義了兩個方法,onSucceed()方法表示當(dāng)服務(wù)器成功相應(yīng)請求時調(diào)用,onFail()表示當(dāng)網(wǎng)絡(luò)請求出現(xiàn)錯誤時調(diào)用。

接著修改HttpUtil中的代碼,

public class HttpUtil {
    public static void sendHttpRequest(final String address, final HttpCallbackInterface httpCallbackInterface) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpURLConnection connection = null;
                try {
                    URL url = new URL(address);
                    connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(8000);
                    connection.setReadTimeout(8000);
                    connection.setDoInput(true);
                    connection.setDoOutput(true);
                    InputStream is = connection.getInputStream();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(is));
                    StringBuilder response = new StringBuilder();
                    String line;
                    while ((line = reader.readLine()) != null) {
                        response.append(line);
                    }
                    if (httpCallbackInterface != null) {
                        //回調(diào)onSucceed()方法
                        httpCallbackInterface.onSucceed(response.toString());
                    }
                } catch (Exception e) {
                    if (httpCallbackInterface != null) {
                        //回調(diào)onFail()方法
                        httpCallbackInterface.onFail(e);
                    }
                } finally {
                    if (connection != null) {
                        connection.disconnect();
                    }
                }
            }
        }).start();
    }
}

我們首先給sendHttpRequest()方法添加了一個HttpCallbackInterface參數(shù),并在方法里開啟了一個子線程,然后在子線程中去執(zhí)行具體的網(wǎng)絡(luò)操作。
注意,子線程中時無法通過return語句來返回?cái)?shù)據(jù)的。
因此,我們這里將服務(wù)器返回的數(shù)據(jù)傳入了onSucceed()方法中,如果出現(xiàn)異常就將異常傳入onFail()方法中。

現(xiàn)在,當(dāng)我們需要調(diào)用sendHttpRequest()進(jìn)行網(wǎng)絡(luò)請求時,

        HttpUtil.sendHttpRequest(address, new HttpCallbackInterface() {
            @Override
            public void onSucceed(String response) {
                //在這里根據(jù)返回內(nèi)容執(zhí)行具體操作
            }

            @Override
            public void onFail(Exception e) {
                //在這里對異常情況進(jìn)行處理
            }
        });

這樣的話,當(dāng)服務(wù)器成功響應(yīng)的時候我們就可以在onSucceed()方法里對響應(yīng)數(shù)據(jù)進(jìn)行處理,類似地,如果出現(xiàn)了異常,就可以在onFail()方法里對異常進(jìn)行處理。如此一來,我們就巧妙地利用回調(diào)機(jī)制將響應(yīng)數(shù)據(jù)成功返回給調(diào)用方了。
另外需要注意的是,onSucceed()方法和onFail()方法最終還是在子線程中運(yùn)行的,因此我們不可以在這里執(zhí)行任何的UI操作,如果需要根據(jù)返回的結(jié)果來更新UI,則仍然要使用異步消息處理機(jī)制(如使用Handler-Looper-MessageQueue機(jī)制)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,923評論 18 139
  • 從三月份找實(shí)習(xí)到現(xiàn)在,面了一些公司,掛了不少,但最終還是拿到小米、百度、阿里、京東、新浪、CVTE、樂視家的研發(fā)崗...
    時芥藍(lán)閱讀 42,366評論 11 349
  • 苦悶的周一,在堵車中開始了正式課程的第一節(jié)課。太陽星座從黃道0度開始,第一個就是白羊座。 白羊座:無法按捺體力的洪...
    草渝田閱讀 251評論 0 5
  • “……不能讓這些人無用地死去……”難道存在有用的死?原本也可能是一個蹩腳司機(jī)忘了踩剎車,一種惡性程度相對高的癌癥,...
    ayan2017閱讀 722評論 0 2
  • 今天私房菜就教大家做一道 皇后“蒜香烤魚” 食材: 鯉魚1千克左右一條,魚肚兩側(cè)橫刀偏開! 配料: 大蒜四頭,生抽...
    享受幸福1閱讀 282評論 0 1