編輯:關於Android編程
我們這片博文就來聊聊這個反響很不錯的OkHttp了,標題是我惡搞的,本篇將著重詳細的分析,探索OkHttp這個框架的使用和封裝
HttpURLConnection HttpClientAndroid系統提供了兩種HTTP通信類
Google推薦使用HttpURLConnection,這個沒必要多說,事實上,我這篇寫的應該算是比較晚了,很多優秀的博文都已經提出了這些觀點了,那我也就不好意思重復的說廢話了,不過我還是得吐槽一下,HttpURLConnection是在是太難用了,而且功能也實在是太少了,雖然Github上封裝的框架還真是不少,不過依然不是特別好用,而Google自己也在尋求解決的辦法,如果你看過android4.4的源碼,你就應該知道,Google把HttpURLConnection替換成了OkHttp,而OkHttp走到現在,已經是相對來說,比較成熟的框架了,那我們為何不去使用它呢?而且現在學習OkHttp的資料和文章實在是太多了,根本不需要什麼學習成本的,搜索一下,馬上就有一大堆,既然如此,我們今兒個就來看看這個花姑涼長什麼樣吧!各位小司機,跟著老司機一起上車吧!
注意,我們使用的IDE是Android Studio
肯定要配置一下啦,我們首先新建一個工程——OkHttpGo,這名字好聽,我就不加demo或者test了,這樣顯得有點low,項目我們基於5.0 Lollipop來開發
http://square.github.io/okhttp/而關於OkHttp的官方介紹,大家可以移步這裡
https://github.com/square/okhttp如果想看源碼,可以去Github上
我們既然要使用,就根據github上來吧,加入依賴,把依賴添加到build.gradle中,當然,他是提供jar的,你如果用Eclipse獲取喜歡用jar,你也可以直接下載jar
compile 'com.squareup.okhttp3:okhttp:3.3.1'
http://square.github.io/picasso/因為我們會用到圖片解析,所以可以加上Picasso的依賴,關於它的介紹,可以移步
這個庫,我下篇博文會介紹到,這裡你只要知道是這麼添加依賴和使用就可以了
compile 'com.squareup.picasso:picasso:2.5.2'
記住,網絡的使用,是需要添加權限的哦!
OkHttp 2.7.5 Jar下載行,大致的配置就到這裡OK了,如果你還有什麼不清楚的,可以去他們官網或者github上瞧一瞧,看一看,這裡再送上一下下載jar的地址吧!
Okio 1.8.0 jar下載OkHttp內部依賴了Okio,這裡也提供了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;
我們可以是這樣的
正方形就搞定了,歐耶!
五.網絡框架封裝
一般的get請求 一般的post請求 基於Http的文件上傳 文件下載 加載圖片 支持請求回調,直接返回對象,對象集合 支持session的保持事實上,我們上面所說的,都還是有些許繁雜了,畢竟我們不應該重復的去寫這麼多麻煩的代碼,對吧,現在我們來對他進行一個封裝,而對於OkHttp,他有以下的幾個功能
我們要封裝一個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什麼的
分享一個下拉刷新的解決辦法,效果圖: Main.java: package example.com.list; import
首先我們要知道一共有哪幾種動畫,這個面試有可能被問哦^_^。 變換動畫(透明度、縮放、平移、旋轉)、逐幀動畫、布局動畫和屬性動畫一、變換動畫我們可以通過XML文件設置動畫
我們通常會在App的UI中嵌入WebView,用來實現某些功能的動態更新。在4.4版本之前,Android WebView基於WebKit實現。不過,在4.4版本之後,A
高通Quick Charge 2.0快充技術(下稱QC2.0),近日成為了我們關注的焦點,同時也是整個行業熱議的話題。在此之前快充只能通過提升電流的方式來達