Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> OkHttp框架從入門到放棄,解析圖片使用Picasso裁剪,二次封裝OkHttpUtils,Post提交表單數據

OkHttp框架從入門到放棄,解析圖片使用Picasso裁剪,二次封裝OkHttpUtils,Post提交表單數據

編輯:關於Android編程

我們這片博文就來聊聊這個反響很不錯的OkHttp了,標題是我惡搞的,本篇將著重詳細的分析,探索OkHttp這個框架的使用和封裝

一.追其原理

Android系統提供了兩種HTTP通信類

HttpURLConnection HttpClient

Google推薦使用HttpURLConnection,這個沒必要多說,事實上,我這篇寫的應該算是比較晚了,很多優秀的博文都已經提出了這些觀點了,那我也就不好意思重復的說廢話了,不過我還是得吐槽一下,HttpURLConnection是在是太難用了,而且功能也實在是太少了,雖然Github上封裝的框架還真是不少,不過依然不是特別好用,而Google自己也在尋求解決的辦法,如果你看過android4.4的源碼,你就應該知道,Google把HttpURLConnection替換成了OkHttp,而OkHttp走到現在,已經是相對來說,比較成熟的框架了,那我們為何不去使用它呢?而且現在學習OkHttp的資料和文章實在是太多了,根本不需要什麼學習成本的,搜索一下,馬上就有一大堆,既然如此,我們今兒個就來看看這個花姑涼長什麼樣吧!各位小司機,跟著老司機一起上車吧!

注意,我們使用的IDE是Android Studio

二.使用准備

肯定要配置一下啦,我們首先新建一個工程——OkHttpGo,這名字好聽,我就不加demo或者test了,這樣顯得有點low,項目我們基於5.0 Lollipop來開發

這裡寫圖片描述

而關於OkHttp的官方介紹,大家可以移步這裡

http://square.github.io/okhttp/

這裡寫圖片描述

如果想看源碼,可以去Github上

https://github.com/square/okhttp

我們既然要使用,就根據github上來吧,加入依賴,把依賴添加到build.gradle中,當然,他是提供jar的,你如果用Eclipse獲取喜歡用jar,你也可以直接下載jar

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

因為我們會用到圖片解析,所以可以加上Picasso的依賴,關於它的介紹,可以移步

http://square.github.io/picasso/

這裡寫圖片描述

這個庫,我下篇博文會介紹到,這裡你只要知道是這麼添加依賴和使用就可以了

compile 'com.squareup.picasso:picasso:2.5.2'

記住,網絡的使用,是需要添加權限的哦!

  
  

行,大致的配置就到這裡OK了,如果你還有什麼不清楚的,可以去他們官網或者github上瞧一瞧,看一看,這裡再送上一下下載jar的地址吧!

OkHttp 2.7.5 Jar下載

OkHttp內部依賴了Okio,這裡也提供了jar下載地址

Okio 1.8.0 jar下載

三.圖片加載

我們先從圖片加載說起,最起碼先定義一下布局呀



 

非常簡陋的一個布局,就一個button和一個imageview,現在我們就是點擊按鈕,然後解析顯示在控件上,這對於OkHttp來說,應該是怎麼使用的呢?注意,現在演示的,都還只是沒有封裝的前提下,我們首先做一些准備工作

    //成功狀態
    private static final int SUCCESS_STATUS = 1;
    //失敗狀態
    private static final int FAIL_STATUS = 2;

    //圖片鏈接
    private String url = "http://d.3987.com/qiz_141118/004.jpg";

這裡我定義了兩個常量,分別是解析成功失敗的狀態,又定義了一張圖片的鏈接,圖片是網上的以上美女圖片,好的,這些都准備好了,現在我們就可以來書寫OkHttp相關的類了

 //圖片解析
        btn_iv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //初始化OkHttp
                OkHttpClient client = new OkHttpClient();
                //構建Request,解析鏈接,這裡可選get/post方法
                final Request request = new Request.Builder().get().url(url).build();
                //添加到請求隊列
                client.newCall(request).enqueue(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        //失敗
                        Log.i(TAG, "解析失敗");
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        //成功
                        Message message = handler.obtainMessage();
                        //判斷,成功就傳值
                        if (response.isSuccessful()) {
                            message.what = SUCCESS_STATUS;
                            message.obj = response.body().bytes();
                            handler.sendMessage(message);
                        } else {
                            handler.sendEmptyMessage(FAIL_STATUS);
                        }
                    }
                });
            }
        });

可以看到,它使用和Volley有點類似,個人感覺,其實也就是那麼幾個步驟,首先初始化,然後設置一下亂七八糟的屬性,最後添加到隊列中,返回兩個回調,成功和失敗,是吧,我們這個時候就直接用handler去發消息了

 //子線程
    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case SUCCESS_STATUS:
                    //拿值
                    byte[] result = (byte[]) msg.obj;
                    //圖片加載
                    Bitmap bitmap = BitmapFactory.decodeByteArray(result, 0, result.length);
                    //設置圖片
                    iv.setImageBitmap(bitmap);
                    break;
                case FAIL_STATUS:
                    //失敗
                    Log.i(TAG, "解析失敗");
                    break;
            }
        }
    };

得出來的效果,用一張圖來表示就綽綽有余了

這裡寫圖片描述

OK,圖片解析的就已經實現了<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjwvYmxvY2txdW90ZT4NCjxoMiBpZD0="四圖片裁剪">四.圖片裁剪

現在呢,我們可以看到是一個美女的圖片,但是如果我們圖片比較大,而我們不需要這麼大,比如長這樣?

這裡寫圖片描述

如果我們不想要這麼大的圖片,又或者說,我們想要一張正方形一樣整齊的圖片,我們該怎麼去做?還記得我們添加的picasso圖片框架嗎?他就可以做到,我們可以用它的功能寫一個工具類來幫助我們裁剪,這個工具類寫起來也沒有多麻煩

package com.lgl.okhttpgo;

import android.graphics.Bitmap;

import com.squareup.picasso.Transformation;

/**
 * 裁剪圖片
 * Created by LGL on 2016/6/19.
 */
public class TailorImageView implements Transformation {

    @Override
    public Bitmap transform(Bitmap source) {

        //得到原圖片的大小,取最小值
        int size = Math.min(source.getWidth(), source.getHeight());
        //長大於寬,還是寬大於長
        int x = (source.getWidth() - size) / 2;
        int y = (source.getHeight() - size) / 2;
        //創建新的bitmap
        Bitmap bitmap = Bitmap.createBitmap(source, x, y, size, size);

        if (bitmap != source) {
            //回收
            source.recycle();
        }
        return bitmap;
    }

    @Override
    public String key() {

        return "lgl";
    }
}

我們使用的話,就在我們解析成功的時候調用就可以了,

case SUCCESS_STATUS:
                    //拿值
                    byte[] result = (byte[]) msg.obj;
                    //圖片加載
                    Bitmap bitmap = new TailorImageView().transform(BitmapFactory.decodeByteArray(result, 0, result.length));
                    //設置圖片
                    iv.setImageBitmap(bitmap);
                    break;

我們可以是這樣的

這裡寫圖片描述

正方形就搞定了,歐耶!

五.網絡框架封裝

事實上,我們上面所說的,都還是有些許繁雜了,畢竟我們不應該重復的去寫這麼多麻煩的代碼,對吧,現在我們來對他進行一個封裝,而對於OkHttp,他有以下的幾個功能

一般的get請求 一般的post請求 基於Http的文件上傳 文件下載 加載圖片 支持請求回調,直接返回對象,對象集合 支持session的保持

我們要封裝一個OkHttp的話,也就是圍繞著他的這幾個功能來二次開發了,好的,小司機們,我們繼續開車吧!污污污污污…..

我們寫一個OkHttpUtils,其實還算是比較簡單的,因為我們實際上沒寫多少內容

package com.lgl.okhttpgo;

import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 * OkHttp的封裝工具類
 * Created by LGL on 2016/6/19.
 */
public class OkHttpUtils {

    //TAG
    private static final String TAG = OkHttpUtils.class.getSimpleName();

    //聲明客戶端
    private OkHttpClient client;
    //防止多個線程同時訪問所造成的安全隱患
    private volatile static OkHttpUtils okHttpUtils;
    //定義提交類型Json
    private static final MediaType JSON = MediaType.parse("application/json;charset=utf-8");
    //定義提交類型String
    private static final MediaType STRING = MediaType.parse("text/x-markdown;charset=utf-8");
    //子線程
    private Handler handler;

    //構造方法
    private OkHttpUtils() {
        //初始化
        client = new OkHttpClient();
        handler = new Handler(Looper.getMainLooper());
    }


    //單例模式
    public static OkHttpUtils getInstance() {
        OkHttpUtils okUtils = null;
        if (okHttpUtils == null) {
            //線程同步
            synchronized (OkHttpUtils.class) {
                if (okUtils == null) {
                    okUtils = new OkHttpUtils();
                    okHttpUtils = okUtils;
                }
            }
        }
        return okUtils;
    }

    /**
     * 請求的返回結果是json字符串
     *
     * @param jsonValue
     * @param callBack
     */
    private void onsuccessJsonStringMethod(final String jsonValue, final FuncJsonString callBack) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (callBack != null) {
                    try {
                        //解析json
                        callBack.onResponse(jsonValue);
                    } catch (Exception e) {

                    }
                }
            }
        });
    }

    /**
     * 求的返回結果是json對象
     *
     * @param jsonValue
     * @param callBack
     */
    private void onsuccessJsonObjectMethod(final String jsonValue, final FuncJsonObject callBack) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (callBack != null) {
                    try {
                        callBack.onResponse(new JSONObject(jsonValue));
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }


    /**
     * 求的返回結果是json數組
     *
     * @param data
     * @param callBack
     */
    private void onsuccessJsonByteMethod(final byte[] data, final FuncJsonObjectByte callBack) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (callBack != null) {
                    callBack.onResponse(data);
                }
            }
        });
    }

    /**
     * 同步請求,不是很常用,因為會阻塞線程
     *
     * @param url
     * @return
     */
    public String syncGetByURL(String url) {
        //構建一個Request請求
        Request request = new Request.Builder().url(url).build();
        Response response = null;

        try {
            //同步請求數據
            response = client.newCall(request).execute();

            if (response.isSuccessful()) {
                return response.body().string();
            }
        } catch (Exception e) {

        }

        return null;
    }


    /**
     * 請求指定的url,返回的結果是json字符串
     *
     * @param url
     * @param callback
     */
    public void syncJsonStringByURL(String url, final FuncJsonString callback) {
        final Request request = new Request.Builder().url(url).build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.i(TAG, "解析失敗");
            }

            //解析成功
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response != null && response.isSuccessful()) {
                    onsuccessJsonStringMethod(response.body().string(), callback);
                }
            }
        });
    }


    /**
     * 返回字符串json的接口
     */
    interface FuncJsonString {
        //處理我們返回的結果
        void onResponse(String result);
    }

    /**
     * 返回json對象的接口
     */
    interface FuncJsonObject {
        //處理我們返回的結果
        void onResponse(JSONObject jsonObject);
    }

    /**
     * 返回json對象的接口
     */
    interface FuncJsonObjectByte {
        //處理我們返回的結果
        void onResponse(byte[] result);
    }

    /**
     * 返回json對象的接口
     */
    interface FuncJsonObjectBitmap {
        //處理我們返回的結果
        void onResponse(Bitmap bitmap);
    }

}

這裡可以看到,我們基本上沒做什麼東西,對吧,只是把常用的方法都復寫作了一些簡單的操作而已,而且我們的注釋也寫的十分詳細,你需要擴展的話,直接擴展就好了,這樣,我們去驗證一下,xml中加上


好的,什麼初始化的我就不寫出來了,直接看點擊事件

 //解析json
        btn_json.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //單例初始化
                OkHttpUtils okHttpUtils = OkHttpUtils.getInstance();
                /**
                 * 地址
                 * 成功回調
                 */
                okHttpUtils.syncJsonStringByURL(json_url, new OkHttpUtils.FuncJsonString() {
                    @Override
                    public void onResponse(String result) {
                        tv_json.setText(result);
                        Log.i(TAG,""+result);
                    }
                });
            }
        });

可以看到,是不是非常的簡單就OK了。我們只要定義傳url進入就可以了,而接口,我們使用的是豆瓣的接口

//json地址
private String json_url = "https://api.douban.com/v2/book/1220562";

這樣我們可以看下運行結果

這裡寫圖片描述

當然,我也是只提供一種思路罷了,這個封裝類並不完善,還需要你自己根據需求來實施,好的,我這裡也就繼續來優化一下了

六.封裝優化

前面可以看到,我們已經封裝好了一個工具類,但是並不完善,現在呢,我們就完善的封裝一下,當然,也只是針對功能點去優化,比如剛才我們只封裝了一個解析返回json字符串,現在我們來一個解析直接返回一個json對象,嘿嘿,怎麼做呢?

     /**
     * 請求指定的url,返回的結果是json對象
     *
     * @param url
     * @param callback
     */
    public void syscJsonObjectByURL(String url, final FuncJsonObject callback) {
        final Request request = new Request.Builder().url(url).build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.i(TAG, "解析失敗");
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response != null && response.isSuccessful()) {
                    onsuccessJsonObjectMethod(response.body().string(), callback);
                }
            }
        });
    }

跟之前的其實很類似,同樣的,我們可以返回byte字節數組

    /**
     * 請求指定的url,返回的結果是byte字節數組
     *
     * @param url
     * @param callback
     */
    public void syscGetByteByURL(String url, final FuncJsonObjectByte callback) {
        final Request request = new Request.Builder().url(url).build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.i(TAG, "解析失敗");
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response != null && response.isSuccessful()) {
                    onsuccessJsonByteMethod(response.body().bytes(), callback);
                }
            }
        });
    }

我們也看到了,我們還剩下Bitmap,我們還自帶裁剪功能哦,哈哈


    /**
     * 請求指定的url,返回的結果是Bitmap
     * @param url
     * @param callback
     */
    public void syscDownloadImageByURL(String url, final FuncJsonObjectBitmap callback){
        final Request request = new Request.Builder().url(url).build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.i(TAG, "解析失敗");
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response != null && response.isSuccessful()) {
                    byte [] data = response.body().bytes();
                    Bitmap bitmap = new TailorImageView().transform(BitmapFactory.decodeByteArray(data,0,data.length));
                    callback.onResponse(bitmap);
                }
            }
        });
    }

到這裡,基本的get封裝就應該差不多寫完了,但是別忘了,論post的重要性,既然如此,那我們就繼續封裝,首先實現的一個功能

post提交表單數據

開發中,也是有諸多需要post的地方的,畢竟安全性,傳輸都是個很不錯的選擇,我們繼續寫方法

 /**
     * 向服務器提交表單
     *
     * @param url      提交地址
     * @param params   提交數據
     * @param callback 提交回調
     */
    public void sendDatafForClicent(String url, Map params, final FuncJsonObject callback) {
        //表單對象,包含input開始的操作
        FormBody.Builder from = new FormBody.Builder();
        //鍵值對不為空,他的值也不為空
        if (params != null && params.isEmpty()) {
            for (Map.Entry entry : params.entrySet()) {
                //裝載表單值
                from.add(entry.getKey(), entry.getValue());
            }
        }
        RequestBody body = from.build();
        //post提交
        Request request = new Request.Builder().url(url).post(body).build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.i(TAG, "解析失敗");
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response != null && response.isSuccessful()) {
                    onsuccessJsonObjectMethod(response.body().string(), callback);
                }
            }
        });
    }

這裡沒有服務端,所以就不能測試了,我這裡也就教大家怎麼使用就好了,首先xml中定義一個按鈕

 

我們可以直接看他的點擊事件

//post表單提交
        btn_post.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                OkHttpUtils okHttpUtils = OkHttpUtils.getInstance();

                //服務端的地址
                String post_url = "";
                //map集合
                HashMap map = new HashMap();
                map.put("username", "LGL");
                map.put("password", "12345678");

                okHttpUtils.sendDatafForClicent(post_url, map, new OkHttpUtils.FuncJsonObject() {
                    @Override
                    public void onResponse(JSONObject jsonObject) {
                        //輸出結果
                        Log.i(TAG, jsonObject.toString());
                    }
                });
            }
        });

OK,這樣就提交了表單,這就是一個完整的封裝過程了,如果你問,那我們普通的請求怎麼辦呢?額,你看了這麼久還不熟悉他的套路?我嘴角微微一笑,你的司機之路還很長啊,咳咳,跑題了,如果大家還有什麼疑問的話,可以去鴻洋那裡看看,我相信現在很多的文章都將了很多的基本使用的,所以我也不是想怎麼去講解析json什麼的

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved