Android 에서 okhttp 3 사용 에 대한 자세 한 설명

23868 단어 Androidokhttp3쓰다
가방
프로젝트 모듈 의 build.gradle 에 okhttp 3 의존 도 를 추가 합 니 다.

compile 'com.squareup.okhttp3:okhttp:3.3.1'
기본 사용
1.okhttp 3 Get 방법
1.1,okhttp 3 동기 화 Get 방법

/**
 *   Get  
 */
private void okHttp_synchronousGet() {
  new Thread(new Runnable() {
    @Override
    public void run() {
      try {
        String url = "https://api.github.com/";
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url(url).build();
        okhttp3.Response response = client.newCall(request).execute();
        if (response.isSuccessful()) {
          Log.i(TAG, response.body().string());
        } else {
          Log.i(TAG, "okHttp is request error");
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }).start();
}
 Request 는 okhttp 3 의 요청 대상 이 고 Response 는 okhttp 3 의 응답 입 니 다.response.isSuccessful()을 통 해 요청 이 성 공 했 는 지 판단 합 니 다.

@Contract(pure=true) 
public boolean isSuccessful()
Returns true if the code is in [200..300), which means the request was successfully received, understood, and accepted.
되 돌아 오 는 데 이 터 를 가 져 옵 니 다.response.body().string()을 통 해 가 져 올 수 있 습 니 다.기본 값 은 utf-8 형식 입 니 다.string()은 작은 데이터 정 보 를 가 져 오 는 데 적 용 됩 니 다.되 돌아 오 는 데이터 가 1M 를 초과 하면 stream()을 사용 하여 되 돌아 오 는 데 이 터 를 가 져 오 는 것 을 권장 합 니 다.string()방법 은 전체 문 서 를 메모리 에 불 러 오기 때 문 입 니 다.

@NotNull 
public final java.lang.String string()
               throws java.io.IOException
Returns the response as a string decoded with the charset of the Content-Type header. If that header is either absent or lacks a charset, this will attempt to decode the response body as UTF-8.
Throws:
java.io.IOException
물론 스 트림 출력 형식 도 가 져 올 수 있 습 니 다.

public final java.io.InputStream byteStream()
1.2,okhttp 3 비동기 Get 방법
가끔 은 파일(예 를 들 어 네트워크 그림)을 다운로드 해 야 합 니 다.만약 에 파일 이 비교적 크 면 전체 다운로드 에 시간 이 걸 립 니 다.보통 우 리 는 시간 이 걸 리 는 작업 스 레 드 에 작업 을 넣 고 okhttp 3 비동기 방법 을 사용 합 니 다.우 리 는 작업 스 레 드 를 열 어 네트워크 요청 을 수행 하지 않 아 도 되 고 돌아 오 는 결과 도 작업 스 레 드 에 있 습 니 다.

/**
 *    Get  
 */
private void okHttp_asynchronousGet(){
  try {
    Log.i(TAG,"main thread id is "+Thread.currentThread().getId());
    String url = "https://api.github.com/";
    OkHttpClient client = new OkHttpClient();
    Request request = new Request.Builder().url(url).build();
    client.newCall(request).enqueue(new okhttp3.Callback() {
      @Override
      public void onFailure(okhttp3.Call call, IOException e) {

      }

      @Override
      public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {
        //  :       ,    
        Log.i(TAG,"callback thread id is "+Thread.currentThread().getId());
        Log.i(TAG,response.body().string());
      }
    });
  } catch (Exception e) {
    e.printStackTrace();
  }
}

주:Android 4.0 이후 네트워크 요청 은 작업 스 레 드 에서 실행 되 어야 하 며 주 스 레 드 에서 실행 할 수 없습니다.따라서 okhttp 3 의 동기 화 Get 방법 을 사용 하려 면 새로운 작업 스 레 드 호출 이 필요 합 니 다.
1.3.요청 헤더 추가
okhttp 3 요청 헤 더 를 추가 하려 면 Request.Builder()에서.header(String key,String value)또는.addHeader(String key,String value)를 사용 해 야 합 니 다.
.header(String key,String value)를 사용 합 니 다.key 가 존재 하면 해당 key 에 대응 하 는 value 를 제거 하고 새 value 를 추가 합 니 다.즉,원래 value 를 교체 합 니 다.
.addHeader(String key,String value)를 사용 합 니 다.현재 값 이 존재 하 더 라 도 새 value 값 만 추가 하고 원래 값 을 제거/교체 하지 않 습 니 다.

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"));
 }

2、okhttp 3 Post 방법
2.1,Post 제출 키 쌍
많은 경우,우 리 는 Post 방식 을 통 해 키 값 을 서버 에 전송 해 야 합 니 다.okhttp 3 는 FormBody.Builder 를 사용 하여 요청 한 매개 변수 키 값 쌍 을 만 듭 니 다.

private void okHttp_postFromParameters() {
  new Thread(new Runnable() {
    @Override
    public void run() {
      try {
        //     url:http://api.k780.com:88/?app=weather.future&weaid=1&&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json
        String url = "http://api.k780.com:88/";
        OkHttpClient okHttpClient = new OkHttpClient();
        String json = "{'app':'weather.future','weaid':'1','appkey':'10003'," +
            "'sign':'b59bc3ef6191eb9f747dd4e83c99f2a4','format':'json'}";
        RequestBody formBody = new FormBody.Builder().add("app", "weather.future")
            .add("weaid", "1").add("appkey", "10003").add("sign",
                "b59bc3ef6191eb9f747dd4e83c99f2a4").add("format", "json")
            .build();
        Request request = new Request.Builder().url(url).post(formBody).build();
        okhttp3.Response response = okHttpClient.newCall(request).execute();
        Log.i(TAG, response.body().string());
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }).start();
}
2.2 、Post a String
Post 방법 으로 문자열 을 보 낼 수 있 지만 1M 이상 의 텍스트 정 보 를 보 내 는 것 은 권장 되 지 않 습 니 다.다음 예제 에 서 는 markdown 텍스트 를 보 냅 니 다.

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
" + "--------
" + "
" + " * _1.0_ May 6, 2013
" + " * _1.1_ June 15, 2013
" + " * _1.2_ August 11, 2013
"; 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()); }
2.3 、Post Streaming
post 는 stream 대상 을 요청 체 로 할 수 있 으 며,Okio 로 데 이 터 를 출력 스 트림 형식 으로 쓸 수 있 습 니 다.

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
"); sink.writeUtf8("-------
"); for (int i = 2; i <= 997; i++) { sink.writeUtf8(String.format(" * %s = %s
", 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()); }
2.4 、Post file

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.기타 설정
3.1,Gson 해석 Response 의 Gson 대상
Response 대상 의 내용 이 json 문자열 이 라면 Gson 을 사용 하여 문자열 을 대상 으로 포맷 할 수 있 습 니 다.Response Body.charStream()은 응답 헤더 에 있 는 Content-Type 을 Response 로 데 이 터 를 되 돌려 주 는 인 코딩 방식 으로 사용 합 니 다.기본 값 은 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.2,okhttp 3 로 컬 캐 시
okhttp 프레임 워 크 전역 에 OkHttpClient 인 스 턴 스(new OkHttpClient()만 있어 야 하 며,인 스 턴 스 를 처음 만 들 때 캐 시 경로 와 크기 를 설정 해 야 합 니 다.설 정 된 캐 시 만 있 으 면 okhttp 기본 값 은 캐 시 기능 을 자동 으로 사용 합 니 다.

package com.jackchan.test.okhttptest;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;

import com.squareup.okhttp.Cache;
import com.squareup.okhttp.CacheControl;
import com.squareup.okhttp.Call;
import com.squareup.okhttp.Callback;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;

import java.io.File;
import java.io.IOException;


public class TestActivity extends ActionBarActivity {

  private final static String TAG = "TestActivity";

  private final OkHttpClient client = new OkHttpClient();

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_test);
    File sdcache = getExternalCacheDir();
    int cacheSize = 10 * 1024 * 1024; // 10 MiB
    client.setCache(new Cache(sdcache.getAbsoluteFile(), cacheSize));
    new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          execute();
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }).start();
  }

  public void execute() 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));

  }
}

okhttpclient 는 응용 프로그램의 개념 과 같 습 니 다.전체 okhttp 의 큰 기능 을 총괄 하고 있 습 니 다.이 를 통 해 캐 시 디 렉 터 리 를 설정 하고 위의 코드 를 실행 하여 얻 은 결 과 는 다음 과 같 습 니 다.

response 1 의 결 과 는 network response 에 있 습 니 다.네트워크 요청 에서 불 러 온 것 을 의미 합 니 다.response 2 의 network response 는 null 이 고 cacheresponse 는 데이터 가 있 습 니 다.캐 시 를 설 정 했 기 때문에 두 번 째 요청 에서 캐 시 에 있 으 면 네트워크 요청 을 하지 않 습 니 다.
그러나 가끔 은 캐 시 가 있 는 상황 에서 도 배경 으로 최신 자원(예 를 들 어 자원 업데이트)을 요청 해 야 할 때 네트워크 데 이 터 를 요청 해 야 한다 고 요구 할 수 있 습 니 다.

public void execute() 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());

    request = request.newBuilder().cacheControl(CacheControl.FORCE_NETWORK).build();
    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 2 대응 하 는 request 가

request = request.newBuilder().cacheControl(CacheControl.FORCE_NETWORK).build();

운행 결 과 를 봅 시다.

response 2 의 cache response 는 null 이 고 network response 는 여전히 데이터 가 있 습 니 다.
같은 우 리 는 FORCE 를 사용 할 수 있다.CACHE 는 캐 시 된 데 이 터 를 사용 하도록 강제 하지만,요청 할 경우 네트워크 에서 가 져 와 야 데이터 가 나 오지 만 FORCE 를 사용 합 니 다.CACHE 정책 은 504 오 류 를 되 돌려 줍 니 다.코드 는 다음 과 같 습 니 다.okhttpclient 의 캐 시 에 가서 request 를 FORCE 로 설정 합 니 다.CACHE

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_test);
    File sdcache = getExternalCacheDir();
    int cacheSize = 10 * 1024 * 1024; // 10 MiB
    //client.setCache(new Cache(sdcache.getAbsoluteFile(), cacheSize));
    new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          execute();
        } catch (Exception e) {
          e.printStackTrace();
          System.out.println(e.getMessage().toString());
        }
      }
    }).start();
  }

  public void execute() 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());

    request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build();
    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));

  }


3.3、okhttp 3 취소 요청
okhttp 3 네트워크 요청 이 더 이상 필요 하지 않 으 면,준비 중인 동기 화/비동기 요청 을 종료 하기 위해 Call.cancel()을 사용 할 수 있 습 니 다.요청 을 쓰 거나 되 돌아 오 는 response 를 읽 고 있 는 스 레 드 가 있 으 면 IOException 을 받 습 니 다.

private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
 private final OkHttpClient client = new OkHttpClient();

 public void run() throws Exception {
  Request request = new Request.Builder()
    .url("http://httpbin.org/delay/2") // This URL is served with a 2 second delay.
    .build();

  final long startNanos = System.nanoTime();
  final Call call = client.newCall(request);

  // Schedule a job to cancel the call in 1 second.
  executor.schedule(new Runnable() {
   @Override public void run() {
    System.out.printf("%.2f Canceling call.%n", (System.nanoTime() - startNanos) / 1e9f);
    call.cancel();
    System.out.printf("%.2f Canceled call.%n", (System.nanoTime() - startNanos) / 1e9f);
   }
  }, 1, TimeUnit.SECONDS);

  try {
   System.out.printf("%.2f Executing call.%n", (System.nanoTime() - startNanos) / 1e9f);
   Response response = call.execute();
   System.out.printf("%.2f Call was expected to fail, but completed: %s%n",
     (System.nanoTime() - startNanos) / 1e9f, response);
  } catch (IOException e) {
   System.out.printf("%.2f Call failed as expected: %s%n",
     (System.nanoTime() - startNanos) / 1e9f, e);
  }
 }

3.4、okhttp 3 시간 초과 설정
okhttp 3 는 연결 시간 초과,읽 기와 쓰기 시간 초과 설정 을 지원 합 니 다.

private final OkHttpClient client;

 public ConfigureTimeouts() throws Exception {
  client = new OkHttpClient.Builder()
    .connectTimeout(10, TimeUnit.SECONDS)
    .writeTimeout(10, TimeUnit.SECONDS)
    .readTimeout(30, TimeUnit.SECONDS)
    .build();
 }

 public void run() throws Exception {
  Request request = new Request.Builder()
    .url("http://httpbin.org/delay/2") // This URL is served with a 2 second delay.
    .build();

  Response response = client.newCall(request).execute();
  System.out.println("Response completed: " + response);
 }

3.5,okhttp 3 재 활용 okhttpclient 설정
모든 HTTP 가 요청 한 프 록 시 설정,시간 초과,캐 시 설정 등 은 OkHttpClient 에 설정 해 야 합 니 다.요청 한 설정 을 변경 하려 면 OkHttpClient.newBuilder()를 사용 하여 builder 대상 을 가 져 올 수 있 습 니 다.이 builder 대상 은 원래 OkHttpClient 와 같은 연결 풀,설정 등 을 공유 합 니 다.
다음 예제 에서'OkHttpClient'설정 2 개 를 복사 한 다음 에 각각 시간 초과 시간 을 설정 합 니 다.

private final OkHttpClient client = new OkHttpClient();

 public void run() throws Exception {
  Request request = new Request.Builder()
    .url("http://httpbin.org/delay/1") // This URL is served with a 1 second delay.
    .build();

  try {
   // Copy to customize OkHttp for this request.
   OkHttpClient copy = client.newBuilder()
     .readTimeout(500, TimeUnit.MILLISECONDS)
     .build();

   Response response = copy.newCall(request).execute();
   System.out.println("Response 1 succeeded: " + response);
  } catch (IOException e) {
   System.out.println("Response 1 failed: " + e);
  }

  try {
   // Copy to customize OkHttp for this request.
   OkHttpClient copy = client.newBuilder()
     .readTimeout(3000, TimeUnit.MILLISECONDS)
     .build();

   Response response = copy.newCall(request).execute();
   System.out.println("Response 2 succeeded: " + response);
  } catch (IOException e) {
   System.out.println("Response 2 failed: " + e);
  }
 }

3.6、okhttp 3 처리 검증
okhttp 3 은 인증 되 지 않 은 요청 을 자동 으로 다시 시도 합 니 다.401 Not Authorized 를 되 돌려 달라 고 요청 할 때 Anthenticator 를 제공 해 야 합 니 다.

 private final OkHttpClient client;

 public Authenticate() {
  client = new OkHttpClient.Builder()
    .authenticator(new Authenticator() {
     @Override public Request authenticate(Route route, Response response) throws IOException {
      System.out.println("Authenticating for response: " + response);
      System.out.println("Challenges: " + response.challenges());
      String credential = Credentials.basic("jesse", "password1");
      return response.request().newBuilder()
        .header("Authorization", credential)
        .build();
     }
    })
    .build();
 }

 public void run() throws Exception {
  Request request = new Request.Builder()
    .url("http://publicobject.com/secrets/hellosecret.txt")
    .build();

  Response response = client.newCall(request).execute();
  if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

  System.out.println(response.body().string());
 }

이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기