1. 程式人生 > >Android中OkHttp使用(包括上傳與下載)

Android中OkHttp使用(包括上傳與下載)


OkHttp介紹

OkHttp是Square公司的出品,一個Http請求庫,Google官方文件不推薦人們使用HttpClient,可是HttpURLConnection 實在是太難用了,因此很多人使用了OkHttp 來解決這問題, Android4.4 的原始碼中HttpURLConnection 已經替換成OkHttp 實現。

使用OkHttp的好處

1、OkHttp 處理了很多網路疑難雜症:會從很多常用的連線問題中自動恢復。如果您的伺服器配置了多個IP地址,當第一個IP連線失敗的時候,OkHttp會自動嘗試下一個IP。OkHttp還處理了代理伺服器問題和SSL握手失敗問題。

2、使用 OkHttp 無需重寫您程式中的網路程式碼。OkHttp實現了幾乎和java.net.HttpURLConnection一樣的API。如果你用了 Apache HttpClient,則OkHttp也提供了一個對應的okhttp-apache 模組。

OkHttp使用方法

1、環境配置

APPbuild.gradle配置依賴包,okHttp依賴okIo所以需要匯入okIo 

compile 'com.squareup.okhttp3:okhttp:3.4.1'
compile 'com.squareup.okio:okio:1.10.0'


AndroidManifest.xml 加入網路許可權

<uses-permission android:name="android.permission.INTERNET" />

2基本使用

2.1、HTTP GET 請求

/**
 * Http Get 請求
 */
private void httpGet() {
    ///建立okHttpClient物件
    OkHttpClient mOkHttpClient = new OkHttpClient();
    //建立一個Request Request是OkHttp中訪問的請求,Builder是輔助類。Response即OkHttp中的響應。
    final Request request = new Request.Builder()
            .url("http://ip.taobao.com/service/getIpInfo.php?ip=63.223.108.42")
            .build();
    //得到一個call物件
    Call call = mOkHttpClient.newCall(request);
    //請求加入排程
    call.enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            //請求失敗
            Log.e("TAG", "請求失敗");
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            //不是UI執行緒,請不要在此更新介面
            String htmlStr = response.body().string();
            Log.e("TAG", "htmlStr ==" + htmlStr);
        }
    });
}
  1. 以上就是傳送一個get請求的步驟,首先構造一個Request物件,引數最起碼有個url,當然你可以通過Request.Builder設定更多的引數比如:headermethod等。

  2. 然後通過request的物件去構造得到一個Call物件,類似於將你的請求封裝成了任務,既然是任務,就會有execute()cancel()等方法。

  3. 最後,以非同步的方式去執行請求,所以我們呼叫的是call.enqueue,將call加入排程佇列,然後等待任務執行完成,我們在Callback中即可得到結果。

3、Http中POST請求
/**
 * Http Post請求
 */
private void httpPost() {
    OkHttpClient mOkHttpClient = new OkHttpClient();
    RequestBody requestBody = new FormBody.Builder()
            .add("ip", "63.223.108.42")
            .build();
    okhttp3.Request request = new okhttp3.Request.Builder()
            .url("http://ip.taobao.com/service/getIpInfo.php?")
            .post(requestBody)
            .build();
    mOkHttpClient.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            //請求失敗
            Log.e("TAG", "請求失敗");
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            String htmlStr = response.body().string();
            Log.e("TAG", "htmlStr ==" + htmlStr);
        }
    });
}

使用Request的post方法來提交請求體RequestBody

RequestBody類為繫結請求引數如果有多個引數繫結方法如下:


 

 

 

RequestBody requestBody = new FormBody.Builder()
        .add("ip", "63.223.108.42")
        .add("ip1", "63.223.108.43")
        .add("ip2", "63.223.108.44")
        .build();

2.3、上傳檔案


在AndroidManifest.xml加入讀取裝置外部儲存空間和sdcard許可權
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

首先需要定義上傳檔案的型別:
public static final MediaType MEDIA_TYPE_MARKDOWN
        = MediaType.parse("text/x-markdown; charset=utf-8");
 
屬性: 
text/html : HTML格式
text/plain :純文字格式      
text/xml :  XML格式
image/gif :gif圖片格式    
image/jpeg :jpg圖片格式 
image/png:png圖片格式
以application開頭的媒體格式型別:

application/xhtml+xml :XHTML格式
application/xml     : XML資料格式
application/atom+xml  :Atom XML聚合格式    
application/json    : JSON資料格式
application/pdf       :pdf格式  
application/msword  : Word文件格式
application/octet-stream : 二進位制流資料(如常見的檔案下載)
application/x-www-form-urlencoded : <form encType=””>中預設的encType,form表單資料被編碼為key/value格式傳送到伺服器(表單預設的提交資料的格式)

另外一種常見的媒體格式是上傳檔案之時使用的:
multipart/form-data : 需要在表單中進行檔案上傳時,就需要使用該格式
注意:MediaType.parse("image/png")裡的"image/png"不知道該填什麼,可以參考---》http://www.w3school.com.cn/media/media_mimeref.asp
如何使用呢?(在請求體裡面寫入型別和需要寫入的資料,通過post請求)
String body = "hdsoifhjoihdsfh";
RequestBody body = RequestBody.create(MEDIA_TYPE_MARKDOWN, body);
sdcard 根目錄的test.txt檔案上傳到伺服器
/**
 * 上傳檔案
 */
private void postAsynFile() {
    OkHttpClient mOkHttpClient = new OkHttpClient();
    File file = new File("/sdcard/test.txt");
    Request request = new Request.Builder()
            .url("https://api.github.com/markdown/raw")
            .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file))
            .build();

    mOkHttpClient.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            Log.e("TAG", "上傳失敗!");
        }

        @Override
        public void onResponse(Call call, Response response) throws IOException {
            Log.e("TAG", response.body().string());
        }
    });
}
注:測試時在test.txt檔案中是什麼文字,伺服器將會把裡面的文字返回表示成功。

2.4、下載檔案

下載檔案實現起來比較簡單,在這裡下載一張圖片,我們得到Response後將流寫進我們指定的圖片檔案中就可以了。
/**
 * 下載檔案
 */
private void downAsynFile() {
    OkHttpClient mOkHttpClient = new OkHttpClient();
    String url = "https://www.baidu.com/img/bd_logo1.png";
    Request request = new Request.Builder().url(url).build();
    mOkHttpClient.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {

        }

        @Override
        public void onResponse(Call call, Response response) {
            InputStream inputStream = response.body().byteStream();
            FileOutputStream fileOutputStream = null;
            try {
                fileOutputStream = new FileOutputStream(new File("/sdcard/baidu.png"));
                byte[] buffer = new byte[2048];
                int len = 0;
                while ((len = inputStream.read(buffer)) != -1) {
                    fileOutputStream.write(buffer, 0, len);
                }
                fileOutputStream.flush();
            } catch (IOException e) {
                Log.e("TAG", "IOException");
                e.printStackTrace();
            }

            Log.d("TAG", "檔案下載成功");
        }
    });
}

OkHttp方法封裝


根據上面程式碼寫多個請求肯定包含大量的重複程式碼,所以需要進行封裝,在GitHub上有個封裝非常好的工具類名為OkHttpUtils,地址:https://github.com/hongyangAndroid/okhttputils

1、OkHttpUtils使用Get請求

 OkHttpClientManager.getAsyn("https://www.baidu.com", new OkHttpClientManager.ResultCallback<String>()
        {
            @Override
            public void onError(Request request, Exception e)
            {
                e.printStackTrace();
            }

            @Override
            public void onResponse(String u)
            {
                mTv.setText(u);//注意這裡是UI執行緒
            }
        });
對於一般的請求,我們希望給個url,然後CallBack裡面直接操作控制元件。

2、OkHttpUtils檔案上傳且攜帶引數

 OkHttpClientManager.postAsyn("http://192.168.1.103:8080/okHttpServer/fileUpload",//
    new OkHttpClientManager.ResultCallback<String>()
    {
        @Override
        public void onError(Request request, IOException e)
        {
            e.printStackTrace();
        }

        @Override
        public void onResponse(String result)
        {

        }
    },//
    file,//第三個引數 檔案
    "mFile",//檔名 對應於http中的<input type="file" name="mFile" >
    new OkHttpClientManager.Param[]{
            new OkHttpClientManager.Param("username", "zhy"),
            new OkHttpClientManager.Param("password", "123")}
        );

3、OkHttpUtils檔案下載 

對於檔案下載,提供url,目標dir,callback即可。
OkHttpClientManager.downloadAsyn(
    "http://192.168.1.103:8080/okHttpServer/files/messenger_01.png",    
    Environment.getExternalStorageDirectory().getAbsolutePath(), 
new OkHttpClientManager.ResultCallback<String>()
    {
        @Override
        public void onError(Request request, IOException e)
        {

        }

        @Override
        public void onResponse(String response)
        {
            //檔案下載成功,這裡回撥的reponse為檔案的absolutePath
        }
});



在Github上有有個封裝好的okhttputils類,使用起來非常方便
https://github.com/hongyangAndroid/okhttputils
該封裝類是鴻洋大神編寫,部落格地址
http://blog.csdn.net/lmj623565791/article/details/47911083