1. 程式人生 > >Android okhttp3的基本使用

Android okhttp3的基本使用

okhttp3的基本使用

一 匯入okhttp3.3.1

compile 'com.squareup.okhttp3:okhttp:3.3.1'
compile 'com.squareup.okio:okio:1.8.0'

這裡提醒一下本人在不匯入com.squareup.okio:okio:1.8.0時連線伺服器時失敗——

二 基本使用


1、okhttp3 Get 方法
1.1 、okhttp3 同步 Get方法

 //同步get方式提交
    private void getRequest() {
        new Thread(new Runnable() {
            @Override
      public
void run() { try { String url = "http://apicloud.mob.com/v1/weather/query?key=146d30f8f3b93&city=長沙&province=湖南"; Request request = new Request.Builder().url(url).build(); Response response = client.newCall(request).execute(); if
(response.isSuccessful()) { String string = response.body().string(); Gson gson = new Gson(); Root root = gson.fromJson(response.body().charStream(),Root.class); Log.i("wxy",root.getRetCode()); Message mag = handler.obtainMessage(); mag.obj = string
; handler.sendMessage(mag); } else { Log.i("wxy", "okHttp is request error"); } } catch (IOException e) { e.printStackTrace(); } } }).start(); }

1.2 、okhttp3 非同步 Get方法

有時候需要下載一份檔案(比如網路圖片),如果檔案比較大,整個下載會比較耗時,通常我們會將耗時任務放到工作執行緒中,而使用okhttp3非同步方法,不需要我們開啟工作執行緒執行網路請求,返回的結果也在工作執行緒中;

private void okHttp_asynchronousGet(){
        try {
            Log.i("wxy","main thread id is "+Thread.currentThread().getId());
            String url = "http://apicloud.mob.com/v1/weather/query?key=146d30f8f3b93&city=長沙&province=湖南";
            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("wxy","callback thread id is "+Thread.currentThread().getId());
                    Log.i("wxy",response.body().string());
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

2 、okhttp3 同步 Get方法
很多時候,我們需要通過Post方式把鍵值對資料傳送到伺服器,okhttp3使用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();
                    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("wxy", response.body().string());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

請求快取

在網路請求中,快取技術是一項應用比較廣泛的技術,需要對請求過的網路資源進行快取,而okhttp也支援這一技術,也使用十分方便,前文漲經常出現的OkHttpclient這個時候就要派送用場了。看下面程式碼

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有點像Application的概念,統籌著整個okhttp的大功能,通過它設定快取目錄,我們執行上面的程式碼,得到的結果如下 效果如下
response1 的結果在networkresponse,代表是從網路請求載入過來的,而response2的networkresponse 就為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));

    }

上面的程式碼中
response2對應的request變成

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

我們看看執行結果
執行結果
response2的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));

    }

這裡寫圖片描述
取消操作

網路操作中,經常會使用到對請求的cancel操作,okhttp的也提供了這方面的介面,call的cancel操作。使用Call.cancel()可以立即停止掉一個正在執行的call。如果一個執行緒正在寫請求或者讀響應,將會引發IOException,同時可以通過Request.Builder.tag(Object tag)給請求設定一個標籤,並使用OkHttpClient.cancel(Object tag)來取消所有帶有這個tag的call。但如果該請求已經在做讀寫操作的時候,cancel是無法成功的,會丟擲IOException異常。

public void canceltest() 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("call is cancel:" + call.isCanceled() + "%n");
            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);
        }
    }

成功取消
這裡寫圖片描述
取消失敗
這裡寫圖片描述
簡單的對於OKHttp的使用就介紹到這裡,下次將重點從原始碼角度介紹整個OKHttp是如何運轉的。

這是我自己寫的簡單的測試程式碼——解析線上的天氣JSON

package com.test.okhttp;

import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.google.gson.Gson;
import java.io.IOException;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class MainActivity extends AppCompatActivity {
    private Button btn_get;
    private Button btn_post;
    OkHttpClient client = new OkHttpClient();
    //本地testJson資料
    String json= "JSON資料";

    //JSON資料不可再子執行緒中轉換輸出,要在主執行緒中轉換輸出。
    Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            String jsonString = (String) msg.obj;
            Gson gson = new Gson();
            Root fromJson = gson.fromJson(jsonString,Root.class);
            Log.i("wxy",fromJson.getRetCode());
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn_get = (Button) findViewById(R.id.btn_get);
        btn_get.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                getRequest();
            }
        });
        btn_post = (Button) findViewById(R.id.btn_post);
    }
    private void testJson(){
        Gson gson = new Gson();
        Root fromJson = gson.fromJson(json,Root.class);
        Log.i("wxy",fromJson.getMsg());
    }
    //同步get方式提交
    private void getRequest() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    String url = "http://apicloud.mob.com/v1/weather/query?key=146d30f8f3b93&city=長沙&province=湖南";
                    Request request = new Request.Builder().url(url).build();
                    Response response = client.newCall(request).execute();
                    if (response.isSuccessful()) {
                        String string = response.body().string();
                        Message mag = handler.obtainMessage();
                        mag.obj = string;
                        handler.sendMessage(mag);
                    } else {
                        Log.i("wxy", "okHttp is request error");
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
    /**
     * 非同步 Get方法
     */
    private void okHttp_asynchronousGet(){
        try {
            Log.i("wxy","main thread id is "+Thread.currentThread().getId());
            String url = "http://apicloud.mob.com/v1/weather/query?key=146d30f8f3b93&city=長沙&province=湖南";
            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("wxy","callback thread id is "+Thread.currentThread().getId());
                    Log.i("wxy",response.body().string());
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Post 提交鍵值對
     * 如果是非同步同get方式非同步提交一致
     */
    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();
                    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("wxy", response.body().string());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

}

下面及時天氣的資料實體

Root.java

package com.test.okhttp;

/**
 * Created by WXY on 2016/6/30.
 */
import java.io.Serializable;
import java.util.List;

public class Root implements Serializable{
    private String msg;

    private List<Result> result ;

    private String retCode;

    public void setMsg(String msg){
        this.msg = msg;
    }
    public String getMsg(){
        return this.msg;
    }
    public void setResult(List<Result> result){
        this.result = result;
    }
    public List<Result> getResult(){
        return this.result;
    }
    public void setRetCode(String retCode){
        this.retCode = retCode;
    }
    public String getRetCode(){
        return this.retCode;
    }
}

Future.java

package com.test.okhttp;

import java.io.Serializable;

/**
 * Created by WXY on 2016/6/30.
 */

public class Future implements Serializable{
    private String date;

    private String dayTime;

    private String night;

    private String temperature;

    private String week;

    private String wind;

    public void setDate(String date){
        this.date = date;
    }
    public String getDate(){
        return this.date;
    }
    public void setDayTime(String dayTime){
        this.dayTime = dayTime;
    }
    public String getDayTime(){
        return this.dayTime;
    }
    public void setNight(String night){
        this.night = night;
    }
    public String getNight(){
        return this.night;
    }
    public void setTemperature(String temperature){
        this.temperature = temperature;
    }
    public String getTemperature(){
        return this.temperature;
    }
    public void setWeek(String week){
        this.week = week;
    }
    public String getWeek(){
        return this.week;
    }
    public void setWind(String wind){
        this.wind = wind;
    }
    public String getWind(){
        return this.wind;
    }
}

Result.java

package com.test.okhttp;

import java.io.Serializable;
import java.util.List;

/**
 * Created by WXY on 2016/6/30.
 */

public class Result  implements Serializable{
    private String airCondition;

    private String city;

    private String coldIndex;

    private String date;

    private String distrct;

    private String dressingIndex;

    private String exerciseIndex;

    private List<Future> future ;

    private String humidity;

    private String pollutionIndex;

    private String province;

    private String sunrise;

    private String sunset;

    private String temperature;

    private String time;

    private String updateTime;

    private String washIndex;

    private String weather;

    private String week;

    private String wind;

    public void setAirCondition(String airCondition){
        this.airCondition = airCondition;
    }
    public String getAirCondition(){
        return this.airCondition;
    }
    public void setCity(String city){
        this.city = city;
    }
    public String getCity(){
        return this.city;
    }
    public void setColdIndex(String coldIndex){
        this.coldIndex = coldIndex;
    }
    public String getColdIndex(){
        return this.coldIndex;
    }
    public void setDate(String date){
        this.date = date;
    }
    public String getDate(){
        return this.date;
    }
    public void setDistrct(String distrct){
        this.distrct = distrct;
    }
    public String getDistrct(){
        return this.distrct;
    }
    public void setDressingIndex(String dressingIndex){
        this.dressingIndex = dressingIndex;
    }
    public String getDressingIndex(){
        return this.dressingIndex;
    }
    public void setExerciseIndex(String exerciseIndex){
        this.exerciseIndex = exerciseIndex;
    }
    public String getExerciseIndex(){
        return this.exerciseIndex;
    }
    public void setFuture(List<Future> future){
        this.future = future;
    }
    public List<Future> getFuture(){
        return this.future;
    }
    public void setHumidity(String humidity){
        this.humidity = humidity;
    }
    public String getHumidity(){
        return this.humidity;
    }
    public void setPollutionIndex(String pollutionIndex){
        this.pollutionIndex = pollutionIndex;
    }
    public String getPollutionIndex(){
        return this.pollutionIndex;
    }
    public void setProvince(String province){
        this.province = province;
    }
    public String getProvince(){
        return this.province;
    }
    public void setSunrise(String sunrise){
        this.sunrise = sunrise;
    }
    public String getSunrise(){
        return this.sunrise;
    }
    public void setSunset(String sunset){
        this.sunset = sunset;
    }
    public String getSunset(){
        return this.sunset;
    }
    public void setTemperature(String temperature){
        this.temperature = temperature;
    }
    public String getTemperature(){
        return this.temperature;
    }
    public void setTime(String time){
        this.time = time;
    }
    public String getTime(){
        return this.time;
    }
    public void setUpdateTime(String updateTime){
        this.updateTime = updateTime;
    }
    public String getUpdateTime(){
        return this.updateTime;
    }
    public void setWashIndex(String washIndex){
        this.washIndex = washIndex;
    }
    public String getWashIndex(){
        return this.washIndex;
    }
    public void setWeather(String weather){
        this.weather = weather;
    }
    public String getWeather(){
        return this.weather;
    }
    public void setWeek(String week){
        this.week = week;
    }
    public String getWeek(){
        return this.week;
    }
    public void setWind(String wind){
        this.wind = wind;
    }
    public String getWind(){
        return this.wind;
    }
}

三、參考文獻:
http://blog.csdn.net/chenzujie/article/details/46994073
http://blog.csdn.net/peak1chen/article/details/51564494