Android:OkHttp的理解和使用
OkHttp的理解和使用
- OkHttp
- 1、什么是OkHttp
- 2、OkHttp的作用
- 3、Okhttp的基本使用
- 3.1、Http請求和響應的組成
- 3.2、OkHttp請求和響應的組成
- 3.3、GET請求同步方法
- 3.4、GET請求異步方法
- 3.5、post請求方法
- 3.6、POST請求傳遞參數的方法總結
- 3.6.1、Post方式提交String
- 3.6.2、Post方式提交 `流`
- 3.6.3、Post方式提交文件
- 3.6.4、Post方式提交表單
- 3.7、POST其他用法
- 3.7.1、提取響應頭
- 3.7.2、使用Gson來解析JSON響應
- 3.7.3、響應緩存
- 3.7.4、響應cookie
- 3.8、綜合實例
- 參考
OkHttp
1、什么是OkHttp
1、網絡請求發展
歷史上Http請求庫優缺點
HttpURLConnection—>Apache HTTP Client—>Volley—->okHttp
2、項目開源地址
https://github.com/square/okhttp
3、OkHttp是什么
- OKhttp是一個網絡請求開源項目,Android網絡請求輕量級框架,支持文件上傳與下載,支持https。
2、OkHttp的作用
OkHttp是一個高效的HTTP庫:
- 支持HTTP/2, HTTP/2通過使用多路復用技術在一個單獨的TCP連接上支持并發, 通過在一個連接上一次性發送多個請求來發送或接收數據
- 如果HTTP/2不可用, 連接池復用技術也可以極大減少延時
- 支持GZIP, 可以壓縮下載體積
- 響應緩存可以直接避免重復請求
- 會從很多常用的連接問題中自動恢復
- 如果您的服務器配置了多個IP地址, 當第一個IP連接失敗的時候, OkHttp會自動嘗試下一個IP OkHttp還處理了代理服務器問題和SSL握手失敗問題
優勢
- 使用 OkHttp無需重寫您程序中的網絡代碼。OkHttp實現了幾乎和java.net.HttpURLConnection一樣的API。如果您用了 Apache HttpClient,則OkHttp也提供了一個對應的okhttp-apache 模塊
3、Okhttp的基本使用
Okhttp的基本使用,從以下五方面講解:
- 1.Get請求(同步和異步)
- 2.POST請求表單(key-value)
- 3.POST請求提交(JSON/String/文件等)
- 4.文件下載
- 5.請求超時設置
加入build.gradle
compile 'com.squareup.okhttp3:okhttp:3.6.0'3.1、Http請求和響應的組成
http請求
所以一個類庫要完成一個http請求, 需要包含 請求方法, 請求地址, 請求協議, 請求頭, 請求體這五部分. 這些都在okhttp3.Request的類中有體現, 這個類正是代表http請求的類. 看下圖:
其中HttpUrl類代表請求地址, String method代表請求方法, Headers代表請求頭, RequestBody代表請求體. Object tag這個是用來取消http請求的標志, 這個我們先不管.
http響應
響應組成圖:
可以看到大體由應答首行, 應答頭, 應答體構成. 但是應答首行表達的信息過多, HTTP/1.1表示訪問協議, 200是響應碼, OK是描述狀態的消息.
根據單一職責, 我們不應該把這么多內容用一個應答首行來表示. 這樣的話, 我們的響應就應該由訪問協議, 響應碼, 描述信息, 響應頭, 響應體來組成.
3.2、OkHttp請求和響應的組成
OkHttp請求
構造一個http請求, 并查看請求具體內容:
final Request request = new Request.Builder().url("https://github.com/").build();我們看下在內存中, 這個請求是什么樣子的, 是否如我們上文所說和請求方法, 請求地址, 請求頭, 請求體一一對應.
OkHttp響應
OkHttp庫怎么表示一個響應:
可以看到Response類里面有Protocol代表請求協議, int code代表響應碼, String message代表描述信息, Headers代表響應頭, ResponseBody代表響應體. 當然除此之外, 還有Request代表持有的請求, Handshake代表SSL/TLS握手協議驗證時的信息, 這些額外信息我們暫時不問.
有了剛才說的OkHttp響應的類組成, 我們看下OkHttp請求后響應在內存中的內容:
final Request request = new Request.Builder().url("https://github.com/").build(); Response response = client.newCall(request).execute();3.3、GET請求同步方法
同步GET的意思是一直等待http請求, 直到返回了響應. 在這之間會阻塞進程, 所以通過get不能在Android的主線程中執行, 否則會報錯.
對于同步請求在請求時需要開啟子線程,請求成功后需要跳轉到UI線程修改UI。
public void getDatasync(){new Thread(new Runnable() {@Overridepublic void run() {try {OkHttpClient client = new OkHttpClient();//創建OkHttpClient對象Request request = new Request.Builder().url("http://www.baidu.com")//請求接口。如果需要傳參拼接到接口后面。.build();//創建Request 對象Response response = null;response = client.newCall(request).execute();//得到Response 對象if (response.isSuccessful()) {Log.d("kwwl","response.code()=="+response.code());Log.d("kwwl","response.message()=="+response.message());Log.d("kwwl","res=="+response.body().string());//此時的代碼執行在子線程,修改UI的操作請使用handler跳轉到UI線程。}} catch (Exception e) {e.printStackTrace();}}}).start(); }此時打印結果如下:
response.code()==200; response.message()OK; res{“code”:200,“message”:success};OkHttpClient實現了Call.Factory接口, 是Call的工廠類, Call負責發送執行請求和讀取響應.
Request代表Http請求, 通過Request.Builder輔助類來構建.
client.newCall(request)通過傳入一個http request, 返回一個Call調用. 然后執行execute()方法, 同步獲得Response代表Http請求的響應. response.body()是ResponseBody類, 代表響應體
注意事項:
1,Response.code是http響應行中的code,如果訪問成功則返回200.這個不是服務器設置的,而是http協議中自帶的。res中的code才是服務器設置的。注意二者的區別。
2,response.body().string()本質是輸入流的讀操作,所以它還是網絡請求的一部分,所以這行代碼必須放在子線程。
3,response.body().string()只能調用一次,在第一次時有返回值,第二次再調用時將會返回null。原因是:response.body().string()的本質是輸入流的讀操作,必須有服務器的輸出流的寫操作時客戶端的讀操作才能得到數據。而服務器的寫操作只執行一次,所以客戶端的讀操作也只能執行一次,第二次將返回null。
4、響應體的string()方法對于小文檔來說十分方便高效. 但是如果響應體太大(超過1MB), 應避免使用 string()方法, 因為它會將把整個文檔加載到內存中.
5、對于超過1MB的響應body, 應使用流的方式來處理響應body. 這和我們處理xml文檔的邏輯是一致的, 小文件可以載入內存樹狀解析, 大文件就必須流式解析.
注解:
responseBody.string()獲得字符串的表達形式, 或responseBody.bytes()獲得字節數組的表達形式, 這兩種形式都會把文檔加入到內存. 也可以通過responseBody.charStream()和responseBody.byteStream()返回流來處理.
3.4、GET請求異步方法
異步GET是指在另外的工作線程中執行http請求, 請求時不會阻塞當前的線程, 所以可以在Android主線程中使用.
這種方式不用再次開啟子線程,但回調方法是執行在子線程中,所以在更新UI時還要跳轉到UI線程中。
下面是在一個工作線程中下載文件, 當響應可讀時回調Callback接口. 當響應頭準備好后, 就會調用Callback接口, 所以讀取響應體時可能會阻塞. OkHttp現階段不提供異步api來接收響應體。
private final OkHttpClient client = new OkHttpClient();public void run() throws Exception {Request request = new Request.Builder().url("http://publicobject.com/helloworld.txt").build();client.newCall(request).enqueue(new Callback() {@Override public void onFailure(Request request, Throwable throwable) {throwable.printStackTrace();}@Override public void onResponse(Response response) throws IOException {if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);Headers responseHeaders = response.headers();for (int i = 0; i < responseHeaders.size(); i++) {System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));}System.out.println(response.body().string());}}); }異步請求的打印結果與注意事項與同步請求時相同。最大的不同點就是異步請求不需要開啟子線程,enqueue方法會自動將網絡請求部分放入子線程中執行。
注意事項:
- 1,回調接口的onFailure方法和onResponse執行在子線程。
- 2,response.body().string()方法也必須放在子線程中。當執行這行代碼得到結果后,再跳轉到UI線程修改UI。
3.5、post請求方法
Post請求也分同步和異步兩種方式,同步與異步的區別和get方法類似,所以此時只講解post異步請求的使用方法。
private void postDataWithParame() {OkHttpClient client = new OkHttpClient();//創建OkHttpClient對象。FormBody.Builder formBody = new FormBody.Builder();//創建表單請求體formBody.add("username","zhangsan");//傳遞鍵值對參數Request request = new Request.Builder()//創建Request 對象。.url("http://www.baidu.com").post(formBody.build())//傳遞請求體.build();client.newCall(request).enqueue(new Callback() {。。。});//回調方法的使用與get異步請求相同,此時略。 }看完代碼我們會發現:post請求中并沒有設置請求方式為POST,回憶在get請求中也沒有設置請求方式為GET,那么是怎么區分請求方式的呢?重點是Request.Builder類的post方法,在Request.Builder對象創建最初默認是get請求,所以在get請求中不需要設置請求方式,當調用post方法時把請求方式修改為POST。所以此時為POST請求。
3.6、POST請求傳遞參數的方法總結
3.6.1、Post方式提交String
下面是使用HTTP POST提交請求到服務. 這個例子提交了一個markdown文檔到web服務, 以HTML方式渲染markdown. 因為整個請求體都在內存中, 因此避免使用此api提交大文檔(大于1MB).
public static final MediaType MEDIA_TYPE_MARKDOWN= MediaType.parse("text/x-markdown; charset=utf-8");private final OkHttpClient client = new OkHttpClient();public void run() throws Exception {String postBody = ""+ "Releases\n"+ "--------\n"+ "\n"+ " * _1.0_ May 6, 2013\n"+ " * _1.1_ June 15, 2013\n"+ " * _1.2_ August 11, 2013\n";Request request = new Request.Builder().url("https://api.github.com/markdown/raw").post(RequestBody.create(MEDIA_TYPE_MARKDOWN, postBody)).build();Response response = client.newCall(request).execute();if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);System.out.println(response.body().string()); }3.6.2、Post方式提交 流
以流的方式POST提交請求體. 請求體的內容由流寫入產生. 這個例子是流直接寫入Okio的BufferedSink. 你的程序可能會使用OutputStream, 你可以使用BufferedSink.outputStream()來獲取. OkHttp的底層對流和字節的操作都是基于Okio庫, Okio庫也是Square開發的另一個IO庫, 填補I/O和NIO的空缺, 目的是提供簡單便于使用的接口來操作IO.
public static final MediaType MEDIA_TYPE_MARKDOWN= MediaType.parse("text/x-markdown; charset=utf-8");private final OkHttpClient client = new OkHttpClient();public void run() throws Exception {RequestBody requestBody = new RequestBody() {@Override public MediaType contentType() {return MEDIA_TYPE_MARKDOWN;}@Override public void writeTo(BufferedSink sink) throws IOException {sink.writeUtf8("Numbers\n");sink.writeUtf8("-------\n");for (int i = 2; i <= 997; i++) {sink.writeUtf8(String.format(" * %s = %s\n", i, factor(i)));}}private String factor(int n) {for (int i = 2; i < n; i++) {int x = n / i;if (x * i == n) return factor(x) + " × " + i;}return Integer.toString(n);}};Request request = new Request.Builder().url("https://api.github.com/markdown/raw").post(requestBody).build();Response response = client.newCall(request).execute();if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);System.out.println(response.body().string()); }3.6.3、Post方式提交文件
public static final MediaType MEDIA_TYPE_MARKDOWN= MediaType.parse("text/x-markdown; charset=utf-8");private final OkHttpClient client = new OkHttpClient();public void run() throws Exception {File file = new File("README.md");Request request = new Request.Builder().url("https://api.github.com/markdown/raw").post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file)).build();Response response = client.newCall(request).execute();if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);System.out.println(response.body().string()); }3.6.4、Post方式提交表單
使用FormEncodingBuilder來構建和HTML標簽相同效果的請求體. 鍵值對將使用一種HTML兼容形式的URL編碼來進行編碼.
private final OkHttpClient client = new OkHttpClient();public void run() throws Exception {RequestBody formBody = new FormBody.Builder().add("search", "Jurassic Park").build();Request request = new Request.Builder().url("https://en.wikipedia.org/w/index.php").post(formBody).build();Response response = client.newCall(request).execute();if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);System.out.println(response.body().string());}3.7、POST其他用法
3.7.1、提取響應頭
典型的HTTP頭像是一個Map<String, String> : 每個字段都有一個或沒有值. 但是一些頭允許多個值, 像Guava的Multimap
例如:
HTTP響應里面提供的Vary響應頭, 就是多值的. OkHttp的api試圖讓這些情況都適用.
- 當寫請求頭的時候, 使用header(name, value)可以設置唯一的name、value. 如果已經有值, 舊的將被移除,然后添加新的. 使用addHeader(name, value)可以添加多值(添加, 不移除已有的).
- 當讀取響應頭時, 使用header(name)返回最后出現的name、value. 通常情況這也是唯一的name、value.如果沒有值, 那么header(name)將返回null. 如果想讀取字段對應的所有值,使用headers(name)會返回一個list.
為了獲取所有的Header, Headers類支持按index訪問.
private final OkHttpClient client = new OkHttpClient();public void run() throws Exception {Request request = new Request.Builder().url("https://api.github.com/repos/square/okhttp/issues").header("User-Agent", "OkHttp Headers.java").addHeader("Accept", "application/json; q=0.5").addHeader("Accept", "application/vnd.github.v3+json").build();Response response = client.newCall(request).execute();if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);System.out.println("Server: " + response.header("Server"));System.out.println("Date: " + response.header("Date"));System.out.println("Vary: " + response.headers("Vary")); }3.7.2、使用Gson來解析JSON響應
Gson是一個在JSON和Java對象之間轉換非常方便的api庫. 這里我們用Gson來解析Github API的JSON響應.
注意: ResponseBody.charStream()使用響應頭Content-Type指定的字符集來解析響應體. 默認是UTF-8.
private final OkHttpClient client = new OkHttpClient();private final Gson gson = new Gson();public void run() throws Exception {Request request = new Request.Builder().url("https://api.github.com/gists/c2a7c39532239ff261be").build();Response response = client.newCall(request).execute();if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);Gist gist = gson.fromJson(response.body().charStream(), Gist.class);for (Map.Entry<String, GistFile> entry : gist.files.entrySet()) {System.out.println(entry.getKey());System.out.println(entry.getValue().content);}}static class Gist {Map<String, GistFile> files;}static class GistFile {String content;}3.7.3、響應緩存
為了緩存響應, 你需要一個你可以讀寫的緩存目錄, 和緩存大小的限制. 這個緩存目錄應該是私有的, 不信任的程序應不能讀取緩存內容.
一個緩存目錄同時擁有多個緩存訪問是錯誤的. 大多數程序只需要調用一次new OkHttp(), 在第一次調用時配置好緩存, 然后其他地方只需要調用這個實例就可以了. 否則兩個緩存示例互相干擾, 破壞響應緩存, 而且有可能會導致程序崩潰.
響應緩存使用HTTP頭作為配置. 你可以在請求頭中添加Cache-Control: max-stale=3600 , OkHttp緩存會支持. 你的服務通過響應頭確定響應緩存多長時間, 例如使用Cache-Control: max-age=9600.
private final OkHttpClient client;public CacheResponse(File cacheDirectory) throws Exception {int cacheSize = 10 * 1024 * 1024; // 10 MiBCache cache = new Cache(cacheDirectory, cacheSize);client = new OkHttpClient();client.setCache(cache); }public void run() throws Exception {Request request = new Request.Builder().url("http://publicobject.com/helloworld.txt").build();Response response1 = client.newCall(request).execute();if (!response1.isSuccessful()) throw new IOException("Unexpected code " + response1);String response1Body = response1.body().string();System.out.println("Response 1 response: " + response1);System.out.println("Response 1 cache response: " + response1.cacheResponse());System.out.println("Response 1 network response: " + response1.networkResponse());Response response2 = client.newCall(request).execute();if (!response2.isSuccessful()) throw new IOException("Unexpected code " + response2);String response2Body = response2.body().string();System.out.println("Response 2 response: " + response2);System.out.println("Response 2 cache response: " + response2.cacheResponse());System.out.println("Response 2 network response: " + response2.networkResponse());System.out.println("Response 2 equals Response 1? " + response1Body.equals(response2Body)); }如果需要阻值response使用緩存, 使用CacheControl.FORCE_NETWORK. 如果需要阻值response使用網絡, 使用CacheControl.FORCE_CACHE.
警告
如果你使用FORCE_CACHE, 但是response要求使用網絡, OkHttp將會返回一個504 Unsatisfiable Request響應.
實例2
package com.enjoy.networkdemo;import android.util.Log;import org.jetbrains.annotations.NotNull; import org.junit.Test;import java.io.File; import java.io.IOException;import okhttp3.Cache; import okhttp3.Call; import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response;public class InterceptorUnitTest {@Testpublic void interceptorTest() {OkHttpClient okHttpClient = new OkHttpClient.Builder().cache(new Cache(new File("C:\\Users\\Administrator\\Desktop"),1024 * 1024)).addNetworkInterceptor(new Interceptor() {@NotNull@Overridepublic Response intercept(@NotNull Chain chain) throws IOException {System.out.println("version:" + chain.request().header("version"));return chain.proceed(chain.request());}}).addInterceptor(new Interceptor() {@NotNull@Overridepublic Response intercept(@NotNull Chain chain) throws IOException {//前置處理Request request = chain.request().newBuilder().addHeader("os", "android").addHeader("version", "1.0").build();Response response = chain.proceed(request);//后置處理return response;}}).build();Request request = new Request.Builder().url("https://www.httpbin.org/get?a=1&b=2").build();// 準備好請求的Call對象Call call = okHttpClient.newCall(request);try {Response response = call.execute();System.out.println(response.body().string());} catch (IOException e) {e.printStackTrace();}} }3.7.4、響應cookie
package com.enjoy.networkdemo;import org.jetbrains.annotations.NotNull; import org.junit.Test;import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map;import okhttp3.Cache; import okhttp3.Call; import okhttp3.Cookie; import okhttp3.CookieJar; import okhttp3.FormBody; import okhttp3.HttpUrl; import okhttp3.Interceptor; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response;public class CookieUnitTest {Map<String, List<Cookie>> cookies = new HashMap<>();@Testpublic void cookieTest() {OkHttpClient okHttpClient = new OkHttpClient.Builder().cookieJar(new CookieJar() {@Overridepublic void saveFromResponse(@NotNull HttpUrl httpUrl, @NotNull List<Cookie> list) {cookies.put(httpUrl.host(), list);}@NotNull@Overridepublic List<Cookie> loadForRequest(@NotNull HttpUrl httpUrl) {List<Cookie> cookies = CookieUnitTest.this.cookies.get(httpUrl.host());return cookies == null ? new ArrayList<>() : cookies;}}).build();FormBody formBody = new FormBody.Builder().add("username", "lanceedu").add("password", "123123").build();Request request = new Request.Builder().url("https://www.wanandroid.com/user/login").post(formBody).build();// 準備好請求的Call對象Call call = okHttpClient.newCall(request);try {Response response = call.execute();System.out.println(response.body().string());} catch (IOException e) {e.printStackTrace();}request = new Request.Builder().url("https://www.wanandroid.com/lg/collect/list/0/json").build();// 準備好請求的Call對象call = okHttpClient.newCall(request);try {Response response = call.execute();System.out.println(response.body().string());} catch (IOException e) {e.printStackTrace();}} }3.8、綜合實例
參考鏈接
activity_main
MainActivity
package com.example.okhttpdemo;import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView;import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.concurrent.TimeUnit;import okhttp3.Call; import okhttp3.Callback; import okhttp3.FormBody; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response;public class MainActivity extends AppCompatActivity implements View.OnClickListener {private Button syncGet;private Button asyncget;private Button post;private Button fileDownload;private TextView tvtext;private String result;private static OkHttpClient client = new OkHttpClient();/*** 在這里直接設置連接超時,靜態方法內,在構造方法被調用前就已經初始話了*/static {client.newBuilder().connectTimeout(10, TimeUnit.SECONDS);client.newBuilder().readTimeout(10, TimeUnit.SECONDS);client.newBuilder().writeTimeout(10, TimeUnit.SECONDS);}private Request request;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initialize();initListener();}/*** 事件監聽*/private void initListener() {syncGet.setOnClickListener(this);asyncget.setOnClickListener(this);post.setOnClickListener(this);fileDownload.setOnClickListener(this);}/*** 初始化布局控件*/private void initialize() {syncGet = (Button) findViewById(R.id.syncGet);asyncget = (Button) findViewById(R.id.asyncget);post = (Button) findViewById(R.id.post);tvtext = (TextView) findViewById(R.id.tv_text);fileDownload = (Button) findViewById(R.id.fileDownload);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.syncGet:initSyncData();break;case R.id.asyncget:initAsyncGet();break;case R.id.post:initPost();break;case R.id.fileDownload:downLoadFile();break;default:break;}}/*** get請求同步方法*/private void initSyncData() {new Thread(new Runnable() {@Overridepublic void run() {try {request = new Request.Builder().url(Contants.SYNC_URL).build();Response response = client.newCall(request).execute();result = response.body().string();runOnUiThread(new Runnable() {@Overridepublic void run() {tvtext.setText(result);Log.d("MainActivity", "hello");}});} catch (Exception e) {e.printStackTrace();}}}).start();}/*** 異步請求*/private void initAsyncGet() {new Thread(new Runnable() {@Overridepublic void run() {request = new Request.Builder().url(Contants.ASYNC_URL).build();client.newCall(request).enqueue(new Callback() {/*** @param call 是一個接口, 是一個準備好的可以執行的request* 可以取消,對位一個請求對象,只能單個請求* @param e*/@Overridepublic void onFailure(Call call, IOException e) {Log.d("MainActivity", "請求失敗");}/**** @param call* @param response 是一個響應請求* @throws IOException*/@Overridepublic void onResponse(Call call, Response response) throws IOException {/*** 通過拿到response這個響應請求,然后通過body().string(),拿到請求到的數據* 這里最好用string() 而不要用toString()* toString()每個類都有的,是把對象轉換為字符串* string()是把流轉為字符串*/result = response.body().string();runOnUiThread(new Runnable() {@Overridepublic void run() {tvtext.setText(result);}});}});}}).start();}/*** 表單提交*/private void initPost() {String url = "http://112.124.22.238:8081/course_api/banner/query";FormBody formBody = new FormBody.Builder().add("type", "1").build();request = new Request.Builder().url(url).post(formBody).build();new Thread(new Runnable() {@Overridepublic void run() {client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {}@Overridepublic void onResponse(Call call, final Response response) throws IOException {runOnUiThread(new Runnable() {@Overridepublic void run() {tvtext.setText("提交成功");}});}});}}).start();}/*** 文件下載地址*/private void downLoadFile() {String url = "http://www.0551fangchan.com/images/keupload/20120917171535_49309.jpg";request = new Request.Builder().url(url).build();OkHttpClient client = new OkHttpClient();client.newCall(request).enqueue(new Callback() {@Overridepublic void onFailure(Call call, IOException e) {}@Overridepublic void onResponse(Call call, Response response) throws IOException {//把請求成功的response轉為字節流InputStream inputStream = response.body().byteStream();/*** 在這里要加上權限 在mainfests文件中* <uses-permission android:name="android.permission.INTERNET"/>* <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>*///在這里用到了文件輸出流FileOutputStream fileOutputStream = new FileOutputStream(new File("/sdcard/logo.jpg"));//定義一個字節數組byte[] buffer = new byte[2048];int len = 0;while ((len = inputStream.read(buffer)) != -1) {//寫出到文件fileOutputStream.write(buffer, 0, len);}//關閉輸出流fileOutputStream.flush();Log.d("wuyinlei", "文件下載成功...");}});}}參考
1、https://blog.csdn.net/fightingXia/article/details/70947701
2、https://blog.csdn.net/chenzujie/article/details/46994073
3、https://blog.csdn.net/weixin_30700099/article/details/95962192
4、https://www.jianshu.com/p/5a12ae6d741a
5、https://www.jianshu.com/p/ca8a982a116b
6、https://wuyinlei.blog.csdn.net/article/details/50579564
總結
以上是生活随笔為你收集整理的Android:OkHttp的理解和使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WAP资源
- 下一篇: 腾讯地图关键字智能提示搜索