Okhttp 簡介 示例 MD

Markdown版本筆記 個人GitHub首頁 個人博客 個人微信 個人郵箱
MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

目錄

OkHttp

okhttp
官網
文檔
API php

You'll also need Okio , which OkHttp uses for fast I/O and resizable調整 buffers。
Okio的API文檔java

compile 'com.squareup.okhttp3:okhttp:3.8.0'
compile 'com.squareup.okio:okio:1.13.0'

okhttp-3.9.0.jar
okio-1.13.0.jarreact

簡介

Android下的網絡框架:android

  • 官方集成的網絡框架包含:HttpUrlConnection、HttpClient、Volley。
  • Volley是android開發團隊在2013年Google I/O大會上推出了一個新的網絡通訊框架。目前Volley中部分代碼仍然藉助於HttpClient中部分功能,然而HttpClient在Android 6.0中已經被剔除掉了,若是想要使用Volley還必須使用一個第三方的jai包。
  • Volley是針對數據量不大,但通訊頻繁的網絡操做,而對於大數據量的網絡操做,好比說下載文件等,Volley的表現就會很是糟糕。
  • 若是使用HttpUrlConnection則要從頭開始封裝對應的操做。

OkHttp是一個 Java 的 HTTP+SPDY 客戶端開發包,同時也支持 Android,須要 Android 2.3 以上,同時還須要一個okio包。git

  • OKHttp是Android(Java)版Http客戶端,很是高效,支持SPDY、鏈接池、GZIP和 HTTP 緩存
  • 默認狀況下,OKHttp會自動處理常見的網絡問題,像二次鏈接、SSL的握手問題
  • 若是你的應用程序中集成了OKHttp,Retrofit默認會使用OKHttp處理其網絡層請求
  • 從Android4.4開始,HttpURLConnection的底層實現採用的是okHttp

PS:
SPDY(讀做「SPeeDY」)是Google開發的基於TCP的應用層協議,用以最小化網絡延遲,提高網絡速度,優化用戶的網絡使用體驗。
SPDY並非一種用於替代HTTP的協議,而是對HTTP協議的加強。
新協議的功能包括數據流的多路複用、請求優先級以及HTTP報頭壓縮。
谷歌表示,引入SPDY協議後,在實驗室測試中頁面加載速度比原先快64%。github

官方 Overview

HTTP is the way modern applications network. It's how we exchange data & media. Doing HTTP efficiently makes your stuff材料、塞滿 load faster and saves bandwidth帶寬.web

OkHttp is an HTTP client that's efficient by default:json

  • HTTP/2 support allows all requests to the same host to share a socket.
  • Connection pooling鏈接池 reduces使變弱 request latency延遲 (if HTTP/2 isn't available).
  • Transparent GZIP透明的GZIP壓縮 shrinks減小 download sizes.
  • Response caching avoids the network completely for repeat重複 requests.

OkHttp perseveres堅忍 when the network is troublesome: it will silently沉默的 recover from common connection problems. If your service has multiple IP addresses, OkHttp will attempt alternate輪流、交替 addresses if the first connect fails. This is necessary for IPv4+IPv6 and for services hosted in redundant冗餘的、多餘的 data centers. OkHttp initiates開始 new connections with modern TLS features (SNI, ALPN), and falls back to TLS 1.0 if the handshake fails.api

Using OkHttp is easy. Its request/response API is designed with fluent流暢的 builders and immutability不變的. It supports both synchronous blocking calls and async calls with callbacks.緩存

OkHttp supports Android 2.3 and above. For Java, the minimum requirement is 1.7.

Works with OkHttp

Here’s some libraries that work nicely with OkHttp.

  • Glide: An image loading and caching library for Android focused on smooth scrolling. 專一於平滑滾動的Android圖像加載和緩存庫。
  • Okio: A modern I/O API for Java. Java的現代I/O API。
  • Retrofit: Type-safe HTTP client for Android and Java by Square. Square公司出的適用於Android和Java的類型安全的HTTP客戶端。
  • Chuck: An in-app HTTP inspector for Android OkHttp clients. 適用於Android OkHttp客戶端的應用內HTTP檢查器。
  • Communicator: An OkHttp wrapper for Scala built with Android in mind. 安裝了Android的Scala的OkHttp包裝器。
  • CWAC-NetSecurity: Simplifying Secure Internet Access. 簡化安全Internet訪問。
  • Fresco: An Android library for managing images and the memory they use. 用於管理圖像和他們使用的內存的Android庫。
  • GoogleAppEngineOkHttp: An OkHttp Call that works on Google App Engine. 適用於Google App Engine的OkHttp調用。
  • ModernHttpClient: Xamarin HTTP API that uses native implementations. 使用本地實現的Xamarin HTTP API。
  • Moshi: A modern JSON library for Android and Java. Android和Java的現代JSON庫。
  • Ok2Curl: Convert OkHttp requests into curl logs. 將OkHttp請求轉換爲curl日誌。
  • okhttp-digest: A digest authenticator for OkHttp. OkHttp的摘要驗證器。
  • OkHttp Idling Resource: An Espresso IdlingResource for OkHttp. OkHttp的濃咖啡空轉資源。
  • okhttp-signpost: OAuth signing with signpost and OkHttp. OAuth簽署路標和OkHttp。
  • okhttp-stats: Get stats like average network speed. 獲取平均網絡速度的統計信息。
  • OkHttp-Xamarin: Xamarin bindings for OkHttp. 用於OkHttp的Xamarin綁定。
  • OkLog: Response logging interceptor for OkHttp. Logs a URL link with URL-encoded response for every OkHttp call. OkHttp的響應記錄攔截器。記錄每一個OkHttp調用的URL編碼響應的URL連接。
  • OkSocial A curl-like client for social networks and other APIs. 社交網絡和其餘API的curl-like客戶端。
  • PersistentCookieJar: A persistent CookieJar. 一個持久的CookieJar。
  • Picasso: A powerful image downloading and caching library for Android. 一個功能強大的Android圖像下載和緩存庫。
  • Smash: A Volley-inspired networking library. 一個受Volley啓發的網絡庫。
  • Stetho: Stetho is a debug bridge for Android applications. Stetho是Android應用程序的調試橋。
  • Thrifty: An implementation of Apache Thrift for Android. 在Android上Apache Thrift的一個實現。
  • Volley-OkHttp-Android: A fork of Volley with changes to work with OkHttp. 使用OkHttp進行更改的fork自Volley的一個庫。

  • Wire: Clean, lightweight protocol buffers for Android and Java. 適用於Android和Java的清潔、輕便的protocol buffers。

示例代碼

get和post示例

public class MainActivity extends ListActivity {
    private User mUser;
    private String mBaseUrl = "http://api.95xiu.com/";
    private OkHttpClient client;

    private TextView mTv;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String[] array = {"post方式提交鍵值對數據", "get方式提交鍵值對數據",};
        mTv = new TextView(this);
        getListView().addFooterView(mTv);
        setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, array));

        client=new OkHttpClient.Builder().build();
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        switch (position) {
            case 0:
                postWithParams(); //post方式提交鍵值對數據
                break;
            case 1:
                getWithParams(); //get方式提交鍵值對數據
                break;
        }
    }

    private void postWithParams() {
        String url = mBaseUrl + "user/loginv2.php";
        FormBody formBody = new FormBody.Builder()
                .add("user", "103468")
                .add("pass", "103468")
                .build();
        Request request = new Request.Builder().url(url).post(formBody).build();
        client.newCall(request)
                .enqueue(new okhttp3.Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        final String responseString = response.body().string();//響應的內容
                        Log.i("bqt", "【body】" + decodeUnicodeToString(responseString));//{"result":0,"msg":"用戶不存在"}

                        mUser = new Gson().fromJson(responseString, User.class);//類型轉換
                        runOnUiThread(() -> mTv.setText(decodeUnicodeToString(responseString)));//線程切換
                    }
                });
    }

    private void getWithParams() {
        String url = mBaseUrl + "app/news/index.php"
                + "?session_id=" + mUser.getMsg().getSession_id()
                + "&uid=" + mUser.getMsg().getId();
        Request request = new Request.Builder().url(url).get().build();
        client.newCall(request)
                .enqueue(new okhttp3.Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        final String responseString = response.body().string();
                        runOnUiThread(() -> mTv.setText(decodeUnicodeToString(responseString)));
                    }
                });
    }

    //將Unicode編碼解析成字符串形式(如漢字)
    public static String decodeUnicodeToString(String uString) {
        StringBuilder sb = new StringBuilder();
        int i = -1, pos = 0;
        while ((i = uString.indexOf("\\u", pos)) != -1) {
            sb.append(uString.substring(pos, i));
            if (i + 5 < uString.length()) {
                pos = i + 6;
                sb.append((char) Integer.parseInt(uString.substring(i + 2, i + 6), 16));
            }
        }
        sb.append(uString.substring(pos));
        return sb.toString();
    }
}

攔截器和證書示例

public class OkHttp_Activity extends ListActivity {

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String[] array = {"應用程序攔截器",
                "網絡攔截器",
                "Rewriting Requests,重寫請求",
                "Rewriting Responses,重寫響應",};
        setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, array));
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        new Thread(() -> {//裏面用的都是同步請求,因此必須在一個子線程中調用
            try {//線程裏面的異常不能在線程外面捕獲或throws
                switch (position) {
                    case 0:
                        loggingInterceptor(true, new LoggingInterceptor());//應用程序攔截器
                        break;
                    case 1:
                        loggingInterceptor(false, new LoggingInterceptor());//網絡攔截器
                        break;
                    case 2:
                        loggingInterceptor(new Random().nextBoolean(), new GzipRequestInterceptor());//重寫請求
                        break;
                    case 3:
                        loggingInterceptor(new Random().nextBoolean(), new ReWriteCacheControlInterceptor());//重寫響應
                        break;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
    }

    private void loggingInterceptor(boolean isApplicationInterceptor, Interceptor interceptor) throws IOException {
        OkHttpClient client;
        if (isApplicationInterceptor) client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
        else client = new OkHttpClient.Builder().addNetworkInterceptor(interceptor).build();

        Request request = new Request.Builder()
                .url("http://publicobject.com/helloworld.txt")
                .header("User-Agent", "OkHttp Example")
                .build();

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

        System.out.println("【響應url】" + response.request().url());
        response.body().close();
    }

    //使用一個自定義的TLS版本和密碼組來構建你本身的鏈接規範
    private void connectionSpecs() {
        ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
                .tlsVersions(TlsVersion.TLS_1_2)
                .cipherSuites(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
                        CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
                        CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256)
                .build();

        OkHttpClient client = new OkHttpClient.Builder()
                .connectionSpecs(Collections.singletonList(spec))
                .build();
    }

    //Certificate Pinning,證書鎖定
    public void certificatePinner() throws Exception {
        CertificatePinner certificatePinner = new CertificatePinner.Builder()
                .add("publicobject.com", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=")
                .build();

        OkHttpClient client = new OkHttpClient.Builder()
                .certificatePinner(certificatePinner)
                .build();

        Request request = new Request.Builder()
                .url("https://publicobject.com/robots.txt")
                .build();

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

        for (java.security.cert.Certificate certificate : response.handshake().peerCertificates()) {
            System.out.println("【】" + CertificatePinner.pin(certificate));
        }
    }

    //攔截器
    class LoggingInterceptor implements Interceptor {
        @Override
        public Response intercept(Interceptor.Chain chain) throws IOException {
            Request request = chain.request();//發出的請求
            long t1 = System.nanoTime();
            System.out.println("【請求】" + String.format("Sending request %s on %s%n%s",
                    request.url(), chain.connection(), request.headers()));

            Response response = chain.proceed(request);//生成與請求對應的響應。這裏是全部HTTP工做發生的地方
            long t2 = System.nanoTime();
            System.out.println("【響應】" + String.format("Received response for %s in %.1fms%n%s",
                    response.request().url(), (t2 - t1) / 1e6d, response.headers()));

            return response;
        }
    }

    //This interceptor compresses the HTTP request body. Many webservers can't handle this!
    class GzipRequestInterceptor implements Interceptor {
        @Override
        public Response intercept(Interceptor.Chain chain) throws IOException {
            Request originalRequest = chain.request();
            if (originalRequest.body() == null || originalRequest.header("Content-Encoding") != null) {
                return chain.proceed(originalRequest);//生成與請求對應的響應
            }

            RequestBody compressedRequestBody = new RequestBody() {
                @Override
                public MediaType contentType() {
                    return originalRequest.body().contentType();
                }

                @Override
                public long contentLength() {
                    return -1; // We don't know the compressed length in advance(提早)!
                }

                @Override
                public void writeTo(BufferedSink sink) throws IOException {
                    BufferedSink gzipSink = Okio.buffer(new GzipSink(sink));
                    originalRequest.body().writeTo(gzipSink);
                    gzipSink.close();
                }
            };

            Request compressedRequest = originalRequest.newBuilder()
                    .header("Content-Encoding", "gzip")//添加、刪除或者替換請求頭
                    .method(originalRequest.method(), compressedRequestBody)//改變請求體
                    .build();
            return chain.proceed(compressedRequest);//從新生成與請求對應的響應
        }
    }

    //Dangerous interceptor that rewrites the server's cache-control header.
    class ReWriteCacheControlInterceptor implements Interceptor {
        @Override
        public Response intercept(Interceptor.Chain chain) throws IOException {
            Response originalResponse = chain.proceed(chain.request());
            return originalResponse.newBuilder()
                    .header("Cache-Control", "max-age=60")//重寫響應頭
                    .build();
        }
    }
}

retrofit okhttp RxJava 綜合示例

依賴

//【retrofit2】
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:converter-gson:2.3.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.3.0'

//【okhttp】
compile 'com.squareup.okhttp3:okhttp:3.8.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.8.0'
compile 'com.squareup.okio:okio:1.13.0'

//【butterknife】
compile 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'

//【rxjava】
compile 'io.reactivex:rxandroid:1.1.0'
compile 'io.reactivex:rxjava:1.1.6'

網絡請求接口定義

public interface GitHubApi {

    @GET("repos/{owner}/{repo}/contributors")
    Call<ResponseBody> contributorsBySimpleGetCall(@Path("owner") String owner, @Path("repo") String repo);

    @GET("repos/{owner}/{repo}/contributors")
    Call<List<Contributor>> contributorsByAddConverterGetCall(@Path("owner") String owner, @Path("repo") String repo);

    @Headers({"Accept: application/vnd.github.v3.full+json", "User-Agent: RetrofitBean-Sample-App", "name:ljd"})
    @GET("repos/{owner}/{repo}/contributors")
    Call<List<Contributor>> contributorsAndAddHeader(@Path("owner") String owner, @Path("repo") String repo);

    @GET("search/repositories")
    Call<RetrofitBean> queryRetrofitByGetCall(@Query("q") String owner, @Query("since") String time, @Query("page") int page, @Query("per_page") int per_Page);

    @GET("search/repositories")
    Call<RetrofitBean> queryRetrofitByGetCallMap(@QueryMap Map<String, String> map);

    @GET("repos/{owner}/{repo}/contributors")
    Observable<List<Contributor>> contributorsByRxJava(@Path("owner") String owner, @Path("repo") String repo);

    @GET("users/{user}")
    Observable<User> userByRxJava(@Path("user") String user);

    @GET("/mobilesafe/shouji360/360safesis/360MobileSafe_6.2.3.1060.apk")
    Call<ResponseBody> retrofitDownload();
}

Activity

public class MainActivity extends ListActivity {
    private TextView tv;
    private static final String baseUrl = "https://api.github.com/";
    private static final String mUserName = "square";//哪一個公司【square】
    private static final String mRepo = "retrofit";//哪一個項目【retrofit】
    private CompositeSubscription mSubscriptions = new CompositeSubscription();

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String[] array = {"一、簡單完整演示retrofit的使用",
                "二、添加Gson轉換器",
                "三、添加okHttp的日誌攔截器Interceptor",
                "四、使用本身封裝的API,演示@Headers",
                "五、演示同步請求",
                "六、演示@Query",
                "七、演示@QueryMap",
                "八、最簡單、完整的retrofit+rxJava示例",
                "九、rxJava+retrofit加強",
                "十、演示文件下載",};
        tv = new TextView(this);
        tv.setTextColor(Color.BLUE);
        getListView().addFooterView(tv);
        setListAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, array));
    }

    @Override
    protected void onDestroy() {
        if (mSubscriptions != null) mSubscriptions.unsubscribe();
        super.onDestroy();
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        switch (position + 1) {
            case 1://簡單完整演示retrofit的使用
                requestGitHubContributorsSimple();
                break;
            case 2://添加Gson轉換器
                requestGitHubContributorsByConverter();
                break;
            case 3://添加okHttp的日誌攔截器Interceptor
                requestGitHubContributorsAddOkHttpLog();
                break;
            case 4://使用本身封裝的API,演示@Headers
                requestGitHubContributorsAddHeader();
                break;
            case 5://演示同步請求
                requestGitHubContributorsBySync();
                break;
            case 6://演示@Query
                requestQueryRetrofitByGet(false);
                break;
            case 7://演示@QueryMap
                requestQueryRetrofitByGet(true);
                break;
            case 8://最簡單、完整的retrofit+rxJava示例
                requestGitHubContributorsByRxJava();
                break;
            case 9://rxJava+retrofit加強
                requestGitHubContributorsWithFullUserInfo();
                break;
            case 10://演示文件下載
                retrofitDownload();
                break;
        }
    }

    //一、簡單示例
    private void requestGitHubContributorsSimple() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .build();
        GitHubApi repo = retrofit.create(GitHubApi.class);
        Call<ResponseBody> call = repo.contributorsBySimpleGetCall(mUserName, mRepo);
        call.enqueue(new Callback<ResponseBody>() {
            @Override
            public void onResponse(@NonNull Call<ResponseBody> call, @NonNull Response<ResponseBody> response) {
                String result = null;
                try {
                    result = response.body().string();
                    if (result == null) return;
                } catch (IOException e) {
                    e.printStackTrace();
                }
                tv.setText("GitHub上對項目的貢獻-1:\n");
                ArrayList<Contributor> list = new Gson().fromJson(result, new TypeToken<List<Contributor>>() {
                        }.getType());
                if (list == null || list.size() == 0) return;
                for (Contributor contributor : list) {
                    tv.append(contributor.login + "    " + contributor.contributions + "\n");
                }
            }

            @Override
            public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) {
                Toast.makeText(MainActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
            }
        });
    }

    //二、添加Gson轉換器
    private void requestGitHubContributorsByConverter() {
        new Retrofit.Builder()
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())//轉換器
                .build()
                .create(GitHubApi.class)
                .contributorsByAddConverterGetCall(mUserName, mRepo)
                .enqueue(new Callback<List<Contributor>>() {
                    @Override
                    public void onResponse(@NonNull Call<List<Contributor>> call, @NonNull Response<List<Contributor>> response) {
                        List<Contributor> list = response.body();
                        tv.setText("GitHub上對項目的貢獻-2:\n");
                        if (list == null || list.size() == 0) return;
                        for (Contributor contributor : list) {
                            tv.append(contributor.login + "    " + contributor.contributions + "\n");
                        }
                    }

                    @Override
                    public void onFailure(@NonNull Call<List<Contributor>> call, @NonNull Throwable t) {
                        Toast.makeText(MainActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
                    }
                });
    }

    //三、添加okHttp的日誌攔截器Interceptor
    private void requestGitHubContributorsAddOkHttpLog() {
        HttpLoggingInterceptor logInterceptor = new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY);

        Retrofit retrofit = new Retrofit.Builder()
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                .client(new OkHttpClient.Builder().addInterceptor(logInterceptor).build())
                .baseUrl(baseUrl)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        retrofit.create(GitHubApi.class)
                .contributorsByAddConverterGetCall(mUserName, mRepo)
                .enqueue(new Callback<List<Contributor>>() {
                    @Override
                    public void onResponse(@NonNull Call<List<Contributor>> call, @NonNull Response<List<com.bqt
                            .retrofit.bean.Contributor>> response) {
                        List<Contributor> list = response.body();
                        tv.setText("GitHub上對項目的貢獻-3:\n");
                        if (list == null || list.size() == 0) return;
                        for (Contributor contributor : list) {
                            tv.append(contributor.login + "    " + contributor.contributions + "\n");
                        }
                    }

                    @Override
                    public void onFailure(@NonNull Call<List<Contributor>> call, @NonNull Throwable t) {
                        Toast.makeText(MainActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
                    }
                });
    }

    //四、使用本身封裝的API,演示@Headers
    private void requestGitHubContributorsAddHeader() {
        createRetrofitService(GitHubApi.class)
                .contributorsAndAddHeader(mUserName, mRepo)
                .enqueue(new Callback<List<Contributor>>() {
                    @Override
                    public void onResponse(@NonNull Call<List<Contributor>> call, @NonNull Response<List<com.bqt
                            .retrofit.bean.Contributor>> response) {
                        List<Contributor> list = response.body();
                        tv.setText("GitHub上對項目的貢獻-4:\n");
                        if (list == null || list.size() == 0) return;
                        for (Contributor contributor : list) {
                            tv.append(contributor.login + "    " + contributor.contributions + "\n");
                        }
                    }

                    @Override
                    public void onFailure(@NonNull Call<List<Contributor>> call, @NonNull Throwable t) {
                    }
                });
    }

    //五、演示同步請求
    private void requestGitHubContributorsBySync() {
        final Call<List<Contributor>> call = createRetrofitService(GitHubApi.class)
                .contributorsByAddConverterGetCall(mUserName, mRepo);
        new Thread(() -> {
            try {
                Response<List<Contributor>> response = call.execute();//在子線程中請求網絡
                final List<Contributor> list = response.body();
                runOnUiThread(() -> {
                    tv.setText("GitHub上對項目的貢獻-5:\n");
                    for (Contributor contributor : list) {
                        tv.append(contributor.login + "    " + contributor.contributions + "\n");
                    }
                });
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
    }

    //6和七、演示@Query和@QueryMap
    private void requestQueryRetrofitByGet(boolean isQueryMap) {
        GitHubApi mGitHubService = createRetrofitService(GitHubApi.class);
        Call<RetrofitBean> call;
        if (!isQueryMap) call = mGitHubService.queryRetrofitByGetCall("retrofit", "2016-03-29", 1, 3);
        else {
            Map<String, String> queryMap = new HashMap<>();
            queryMap.put("q", "retrofit");
            queryMap.put("since", "2016-03-29");
            queryMap.put("page", "1");
            queryMap.put("per_page", "3");
            call = mGitHubService.queryRetrofitByGetCallMap(queryMap);
        }

        call.enqueue(new Callback<RetrofitBean>() {
            @Override
            public void onResponse(@NonNull Call<RetrofitBean> call, @NonNull Response<RetrofitBean> response) {
                RetrofitBean retrofitBean = response.body();
                if (retrofitBean == null) return;
                List<Item> list = retrofitBean.getItems();
                if (list == null || list.size() == 0) return;

                tv.setText(new SimpleDateFormat("yyyy.MM.dd HH:mm:ss SSS", Locale.getDefault()).format(new Date()));
                tv.append("\ntotal:" + retrofitBean.getTotalCount() + "\nincompleteResults:" + retrofitBean.getIncompleteResults());
                for (Item item : list) {
                    tv.append("\n\n【name】" + item.name);
                    tv.append("\n【full_name】" + item.full_name);
                    tv.append("\n【 description】" + item.description);
                }
            }

            @Override
            public void onFailure(@NonNull Call<RetrofitBean> call, @NonNull Throwable t) {
            }
        });
    }

    //八、最簡單、完整的retrofit+rxJava示例
    private void requestGitHubContributorsByRxJava() {
        createRetrofitService(GitHubApi.class)
            .contributorsByRxJava(mUserName, mRepo)//
            .subscribeOn(Schedulers.io())//
            .observeOn(AndroidSchedulers.mainThread())//
            .subscribe(...);
    }

    //九、rxJava+retrofit加強
    private void requestGitHubContributorsWithFullUserInfo() {
        Subscription subscription = createRetrofitService(GitHubApi.class)
            .contributorsByRxJava(mUserName, mRepo)//
            .flatMap(...)
            .flatMap(...)
            .subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(...;
        mSubscriptions.add(subscription);
    }

    //十、演示文件下載
    public void retrofitDownload() {
        //監聽下載進度
        final ProgressDialog dialog = new ProgressDialog(this);
        dialog.setProgressNumberFormat("%1d KB/%2d KB");
        dialog.setTitle("下載");
        dialog.setMessage("正在下載,請稍後...");
        dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        dialog.setCancelable(false);
        dialog.show();

        ProgressHelper.setProgressHandler(new DownloadProgressHandler() {
            @Override
            protected void onProgress(long bytesRead, long contentLength, boolean done) {
                //在主線程中運行
                dialog.setMax((int) (contentLength / 1024));
                dialog.setProgress((int) (bytesRead / 1024));
                if (done) dialog.dismiss();
            }
        });

        Retrofit retrofit = new Retrofit.Builder()//
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())//
                .addConverterFactory(GsonConverterFactory.create())//
                .baseUrl("http://msoftdl.360.cn")
                .client(ProgressHelper.addProgress(null).build())
                .build();

        retrofit.create(GitHubApi.class).retrofitDownload()
                .enqueue(new Callback<ResponseBody>() {
                    @Override
                    public void onResponse(@NonNull Call<ResponseBody> call, @NonNull Response<ResponseBody> response) {
                        try {
                            InputStream is = response.body().byteStream();
                            File file = new File(Environment.getExternalStorageDirectory(), "12345.apk");
                            FileOutputStream fos = new FileOutputStream(file);
                            BufferedInputStream bis = new BufferedInputStream(is);
                            byte[] buffer = new byte[1024];
                            int len;
                            while ((len = bis.read(buffer)) != -1) {
                                fos.write(buffer, 0, len);
                                fos.flush();
                            }
                            fos.close();
                            bis.close();
                            is.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

                    @Override
                    public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) {
                    }
                });
    }

    public static <T> T createRetrofitService(final Class<T> service) {
        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor()
            .setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient.Builder builder = new OkHttpClient.Builder().addInterceptor(httpLoggingInterceptor);
        Retrofit retrofit = new Retrofit.Builder()//
                .client(ProgressHelper.addProgress(builder).build())//
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())//
                .addConverterFactory(GsonConverterFactory.create())//
                .baseUrl("https://api.github.com/")//
                .build();
        return retrofit.create(service);
    }
}

綜合配置

請求參數封裝:

public interface BqtService {
    @GET("User")
    Observable<BqtRes<User>> getUser();

    @FormUrlEncoded
    @POST("BuyInfo/buyRecord")
    Observable<BqtRes<ArrayList<MyClassBean>>> getHistory(@Field("user_id") int uid, @Field("page") int page);
}

調用示例:

H.h().getUser()
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(response -> L.i("onNext " + response.data.toString());//這裏response.data的類型便是User

retrofit、okhttp、RxJava、Gson、攔截器、Header等配置

public class H {
    private static Interceptor buildInterceptor() {
        final String token = AccountManager.getInstance().getToken();
        PackageInfo packInfo = null;
        try {
            packInfo = App.app.getPackageManager().getPackageInfo(App.app.getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        final int version = packInfo == null ? 1 : packInfo.versionCode;
        return new Interceptor() {//應用程序攔截器,只被調用一次
            @Override
            public okhttp3.Response intercept(Chain chain) throws IOException {
                Request request = chain.request()
                        .newBuilder()
                        .addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
                        .addHeader("Accept-Encoding", "gzip, deflate")
                        .addHeader("Connection", "keep-alive")
                        .addHeader("Accept", "*/*")
                        //****************************************自定義Header
                        .addHeader("version", version + "")//app版本號
                        .addHeader("token", token == null ? "" : token)//登陸後返回的token
                        .addHeader("mobile", "1")// 0-PC,1-Android,2-IOS,3-web
                        .build();
                return chain.proceed(request);
            }
        };
    }

    private static Interceptor buildLogInterceptor() {
        return new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
            @Override
            public void log(String message) {
                L.d(message);//這裏會打印出大量的日誌出來,因此不要和手動打印的日誌混在一塊兒
            }
        }).setLevel(HttpLoggingInterceptor.Level.BODY);//日誌顯示級別
    }

    private static OkHttpClient buildOkHttp() {
        return new OkHttpClient.Builder()
                .addInterceptor(buildHeaderInterceptor())//自定義Header
                .addInterceptor(buildLogInterceptor())//日誌攔截
                .connectTimeout(5, TimeUnit.SECONDS)
                .build();
    }

    private static Gson buildGson() {
        return new GsonBuilder()//配置你的Gson
                .setDateFormat("yyyy-MM-dd hh:mm:ss")
                .setPrettyPrinting()
                .serializeNulls()
                .create();
    }

    private static String buildBaseUrl() {
        switch (UrlHelper.getEnv()) {
            case 0: // baseUlr 必須以 / 結束,否則會拋出一個IllegalArgumentException
                return "http://test.talk.99cj.com.cn/";
            case 1:
                return "http://wechat.99cj.com.cn/";
            default:
                return "http://wechat.99cj.com.cn/";
        }
    }

    private static Retrofit buildRetrofit(OkHttpClient client, Converter.Factory converterFactory, CallAdapter.Factory callAdapterFactory) {
        return new Retrofit.Builder()
                .baseUrl(buildBaseUrl())
                .client(client)
                .addConverterFactory(converterFactory)//能夠接收自定義的Gson,固然也能夠不傳
                .addCallAdapterFactory(callAdapterFactory)
                .build();
    }

    private static <T> T createRetrofitService(final Class<T> service) {
        Retrofit retrofit = buildRetrofit(buildOkHttp(), //
                GsonConverterFactory.create(buildGson()),//
                RxJavaCallAdapterFactory.create());//
        return retrofit.create(service);
    }

    public static BqtService h() {
        return createRetrofitService(BqtService.class);
    }
}

添加上述【HttpLoggingInterceptor】攔截器後會打印以下日誌

2017-06-20

相關文章
相關標籤/搜索