Android OkHttp的簡(jiǎn)單使用和封裝詳解
Android OkHttp的簡(jiǎn)單使用和封裝詳解
1,昨天把okHttp仔細(xì)的看了一下,以前都是調(diào)用同事封裝好了的網(wǎng)絡(luò)框架,直接使用很容易,但自己封裝卻不是那么簡(jiǎn)單,還好,今天就來(lái)自我救贖一把,就和大家寫寫從最基礎(chǔ)的OKHttp的簡(jiǎn)單get、post的使用,再到它的封裝。
2,OkHttp的簡(jiǎn)單使用
首先我們創(chuàng)建一個(gè)工程,并在布局文件中添加三個(gè)控件,TextView(用于展示獲取到j(luò)son后的信息)、Button(點(diǎn)擊開(kāi)始請(qǐng)求網(wǎng)絡(luò))、ProgressBar(網(wǎng)絡(luò)加載提示框)
①簡(jiǎn)單的異步Get請(qǐng)求
第一步,創(chuàng)建OKHttpClient對(duì)象
第二步,創(chuàng)建Request請(qǐng)求
第三步,創(chuàng)建一個(gè)Call對(duì)象
第四步,將請(qǐng)求添加到調(diào)度中
不多說(shuō),直接上代碼:
//okHttp的基本使用 --- get方法 String url = "https://api.douban.com/v2/movie/top250?start=0&count=10"; //1,創(chuàng)建OKHttpClient對(duì)象 OkHttpClient mOkHttpClient = new OkHttpClient(); //2,創(chuàng)建一個(gè)Request Request request = new Request.Builder().url(url).build(); //3,創(chuàng)建一個(gè)call對(duì)象 Call call = mOkHttpClient.newCall(request); //4,將請(qǐng)求添加到調(diào)度中 call.enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { } @Override public void onResponse(Response response) throws IOException { if (response.isSuccessful()) { final String message = response.body().string(); handler.post(new Runnable() { @Override public void run() { tv_message.setText(message); progressBar.setVisibility(View.GONE); } }); } } });
效果如下:
注意,由于我們調(diào)用的enqueue()方法,是運(yùn)行在網(wǎng)絡(luò)線程中的,所以當(dāng)我們得到j(luò)son數(shù)據(jù)后想要獲取更新UI的話,可以開(kāi)使用handle.post()方法在run方法里面更新UI。
?、?nbsp;簡(jiǎn)單的異步Post請(qǐng)求
這里的Post請(qǐng)求我們以最常見(jiàn)的注冊(cè)登錄來(lái)舉例。post請(qǐng)求的步驟和get是相似的只是在創(chuàng)建Request的 時(shí)候?qū)⒎?wù)器需要的參數(shù)傳遞進(jìn)去.
代碼如下:
String url = "http://192.168.1.123:8081/api/login"; //1,創(chuàng)建OKhttpClient對(duì)象 OkHttpClient mOkHttpClient = new OkHttpClient(); //2,創(chuàng)建Request RequestBody formBody = new FormEncodingBuilder() .add("username", "superadmin") .add("pwd", "ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413") .build(); Request request = new Request.Builder().url(url).post(formBody).build(); //3,創(chuàng)建call對(duì)象并將請(qǐng)求對(duì)象添加到調(diào)度中 mOkHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { } @Override public void onResponse(Response response) throws IOException { Log.i("wangjitao", response.body().string()); } });
看一下我們服務(wù)器的斷點(diǎn)
可以看到我們服務(wù)器的確拿到了我們傳遞參數(shù),再看一下我們請(qǐng)求后拿到的數(shù)據(jù)
ok,這樣的話我們的post方法就沒(méi)什么問(wèn)題了
3,OkHttp的封裝
由于是封裝我們可以吧OKHttp和Gson給結(jié)合起來(lái),那么我們?cè)趃radle文件添加以下的依賴
compile "com.squareup.okhttp:okhttp:2.4.0" compile 'com.squareup.okio:okio:1.5.0' compile "com.google.code.gson:gson:2.8.0"
?、貱allBack的創(chuàng)建
首選我們知道,當(dāng)接口請(qǐng)求成功或者失敗的時(shí)候我們需要將這個(gè)信息通知給用戶,那么我們就需要?jiǎng)?chuàng)建一個(gè)抽象類RequestCallBack,請(qǐng)求前、成功、失敗、請(qǐng)求后這幾個(gè)方法,創(chuàng)建OnBefore()、OnAfter()、OnError()、OnResponse()對(duì)應(yīng)
/** * 在請(qǐng)求之前的方法,一般用于加載框展示 * * @param request */ public void onBefore(Request request) { } /** * 在請(qǐng)求之后的方法,一般用于加載框隱藏 */ public void onAfter() { } /** * 請(qǐng)求失敗的時(shí)候 * * @param request * @param e */ public abstract void onError(Request request, Exception e); /** * * @param response */ public abstract void onResponse(T response);
由于我們每次想要的數(shù)據(jù)不一定,所以這里我們用<T>來(lái)接收想要裝成的數(shù)據(jù)格式,并通過(guò)反射得到想要的數(shù)據(jù)類型(一般是Bean、List)之類 ,所以RequestCallBack的整體代碼如下:
package com.qianmo.httprequest.http; import com.google.gson.internal.$Gson$Types; import com.squareup.okhttp.Request; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; /** * Created by wangjitao on 15/10/16. * 抽象類,用于請(qǐng)求成功后的回調(diào) */ public abstract class ResultCallback<T> { //這是請(qǐng)求數(shù)據(jù)的返回類型,包含常見(jiàn)的(Bean,List等) Type mType; public ResultCallback() { mType = getSuperclassTypeParameter(getClass()); } /** * 通過(guò)反射想要的返回類型 * * @param subclass * @return */ static Type getSuperclassTypeParameter(Class<?> subclass) { Type superclass = subclass.getGenericSuperclass(); if (superclass instanceof Class) { throw new RuntimeException("Missing type parameter."); } ParameterizedType parameterized = (ParameterizedType) superclass; return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]); } /** * 在請(qǐng)求之前的方法,一般用于加載框展示 * * @param request */ public void onBefore(Request request) { } /** * 在請(qǐng)求之后的方法,一般用于加載框隱藏 */ public void onAfter() { } /** * 請(qǐng)求失敗的時(shí)候 * * @param request * @param e */ public abstract void onError(Request request, Exception e); /** * * @param response */ public abstract void onResponse(T response); }
?、趯?duì)Get、Post方法的簡(jiǎn)單封裝
首先我們創(chuàng)建一個(gè)OkHttpClientManager類,由于是管理類,所以,單例加靜態(tài)對(duì)象搞起
private static OkHttpClientManager mInstance; public static OkHttpClientManager getInstance() { if (mInstance == null){ synchronized (OkHttpClientManager.class) { if (mInstance == null) { mInstance = new OkHttpClientManager(); } } } return mInstance; }
在創(chuàng)建Manager對(duì)象的時(shí)候我們要把OkHttp的一些參數(shù)配置一下,順便一提一下,由于我們我們異步get、post方法是運(yùn)行在子線程中,所以這里我們添加了分發(fā)的 Handler mDelivery;,重寫的OkHttpClientManager構(gòu)造方法如下:
private OkHttpClientManager() { mOkHttpClient = new OkHttpClient(); mOkHttpClient.setConnectTimeout(10, TimeUnit.SECONDS); mOkHttpClient.setWriteTimeout(10, TimeUnit.SECONDS); mOkHttpClient.setReadTimeout(30, TimeUnit.SECONDS); //cookie enabled mOkHttpClient.setCookieHandler(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER)); mDelivery = new Handler(Looper.getMainLooper()); mGson = new Gson(); }
前面的外部調(diào)用對(duì)象封裝好了,這里我們開(kāi)始來(lái)封裝Get或Post方法,我這里以Post方法為例子,首先分析一下,post方法會(huì)有幾個(gè)參數(shù),參數(shù)一url,參數(shù)二參數(shù)params,參數(shù)三Callback(及我們上面的RequestCallBack)參數(shù)四flag(用于取消請(qǐng)求操作,可為空),基礎(chǔ)代碼如下:
/** * 通用基礎(chǔ)的異步的post請(qǐng)求 * @param url * @param callback * @param tag */ public void postAsyn(String url, Param[] params, final ResultCallback callback, Object tag) { Request request = buildPostFormRequest(url, params, tag); deliveryResult(callback, request); }
那么我們?cè)倏匆幌耫eliveryResult方法到底是干什么的
/** * 請(qǐng)求回調(diào)處理方法并傳遞返回值 * @param callback Map類型請(qǐng)求參數(shù) * @param request Request請(qǐng)求 */ private void deliveryResult(ResultCallback callback, Request request) { if (callback == null) callback = DEFAULT_RESULT_CALLBACK; final ResultCallback resCallBack = callback; //UI thread callback.onBefore(request); mOkHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(final Request request, final IOException e) { sendFailedStringCallback(request, e, resCallBack); } @Override public void onResponse(final Response response) { try { final String responseMessage=response.message(); final String responseBody = response.body().string(); if(response.code()==200){ if (resCallBack.mType == String.class) { sendSuccessResultCallback(responseBody, resCallBack); } else { Object o = mGson.fromJson(responseBody, resCallBack.mType); sendSuccessResultCallback(o, resCallBack); } }else{ Exception exception=new Exception(response.code()+":"+responseMessage); sendFailedStringCallback(response.request(), exception, resCallBack); } } catch (IOException e) { sendFailedStringCallback(response.request(), e, resCallBack); } catch (com.google.gson.JsonParseException e) {//Json解析的錯(cuò)誤 sendFailedStringCallback(response.request(), e, resCallBack); } } }); }
可以看到,這個(gè)方法主要是發(fā)出請(qǐng)求并對(duì)請(qǐng)求后的數(shù)據(jù)開(kāi)始回調(diào),這樣我們就基本上封裝好了一個(gè)post方法了 ,把代碼這一部分的代碼貼出來(lái)看看
public class OkHttpClientManager { private static final String TAG = "com.qianmo.httprequest.http.OkHttpClientManager"; private static OkHttpClientManager mInstance; //默認(rèn)的請(qǐng)求回調(diào)類 private final ResultCallback<String> DEFAULT_RESULT_CALLBACK = new ResultCallback<String>(){ @Override public void onError(Request request, Exception e) {} @Override public void onResponse(String response) {} }; private OkHttpClient mOkHttpClient; private Handler mDelivery; private Gson mGson; private GetDelegate mGetDelegate = new GetDelegate(); private PostDelegate mPostDelegate = new PostDelegate(); private DownloadDelegate mDownloadDelegate = new DownloadDelegate(); private OkHttpClientManager() { mOkHttpClient = new OkHttpClient(); mOkHttpClient.setConnectTimeout(10, TimeUnit.SECONDS); mOkHttpClient.setWriteTimeout(10, TimeUnit.SECONDS); mOkHttpClient.setReadTimeout(30, TimeUnit.SECONDS); //cookie enabled mOkHttpClient.setCookieHandler(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER)); mDelivery = new Handler(Looper.getMainLooper()); mGson = new Gson(); } public static OkHttpClientManager getInstance() { if (mInstance == null){ synchronized (OkHttpClientManager.class) { if (mInstance == null) { mInstance = new OkHttpClientManager(); } } } return mInstance; } /** * 外部可調(diào)用的Post異步請(qǐng)求方法 * @param url 請(qǐng)求url * @param params * @param callback 請(qǐng)求完成后回調(diào)類 */ public static void postAsyn(String url, Map<String, String> params, final ResultCallback callback) { getInstance().getPostDelegate().postAsyn(url, params, callback, null); } /** * 異步的post請(qǐng)求 * @param url * @param params * @param callback * @param tag */ public void postAsyn(String url, Map<String, String> params, final ResultCallback callback, Object tag) { Param[] paramsArr = map2Params(params); postAsyn(url, paramsArr, callback, tag); } /** * 通用基礎(chǔ)的異步的post請(qǐng)求 * @param url * @param callback * @param tag */ public void postAsyn(String url, Param[] params, final ResultCallback callback, Object tag) { Request request = buildPostFormRequest(url, params, tag); deliveryResult(callback, request); } /** * 請(qǐng)求回調(diào)處理方法并傳遞返回值 * @param callback Map類型請(qǐng)求參數(shù) * @param request Request請(qǐng)求 */ private void deliveryResult(ResultCallback callback, Request request) { if (callback == null) callback = DEFAULT_RESULT_CALLBACK; final ResultCallback resCallBack = callback; //UI thread callback.onBefore(request); mOkHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(final Request request, final IOException e) { sendFailedStringCallback(request, e, resCallBack); } @Override public void onResponse(final Response response) { try { final String responseMessage=response.message(); final String responseBody = response.body().string(); if(response.code()==200){ if (resCallBack.mType == String.class) { sendSuccessResultCallback(responseBody, resCallBack); } else { Object o = mGson.fromJson(responseBody, resCallBack.mType); sendSuccessResultCallback(o, resCallBack); } }else{ Exception exception=new Exception(response.code()+":"+responseMessage); sendFailedStringCallback(response.request(), exception, resCallBack); } } catch (IOException e) { sendFailedStringCallback(response.request(), e, resCallBack); } catch (com.google.gson.JsonParseException e) {//Json解析的錯(cuò)誤 sendFailedStringCallback(response.request(), e, resCallBack); } } }); } /** * 處理請(qǐng)求成功的回調(diào)信息方法 * @param object 服務(wù)器響應(yīng)信息 * @param callback 回調(diào)類 */ private void sendSuccessResultCallback(final Object object, final ResultCallback callback) { mDelivery.post(() -> { callback.onResponse(object); callback.onAfter(); }); } }
這樣我們就把Post方法封裝好了,同理Get方法,ok,現(xiàn)在我們可以來(lái)調(diào)用調(diào)用了,在調(diào)用之前我們可以對(duì)返回?cái)?shù)據(jù)格式再來(lái)封裝封裝,一般我們后臺(tái)返回的數(shù)據(jù)格式是類似如下:
{ "code": 200, "data": {}, "message": "登錄成功" }
而data中有可能是對(duì)象,也有可能是數(shù)組,所以我們用兩個(gè)類來(lái)實(shí)現(xiàn)一下
CommonResultBean
package com.qianmo.httprequest.bean; /** * 服務(wù)端返回通用接收實(shí)體 * Created by wangjitao on 15/10/30. */ public class CommonResultBean<T> { private String code; private T data; private String message; public String getCode() { return code; } public void setCode(String code) { this.code = code; } public T getData() { return data; } public void setData(T data) { this.data = data; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
CommonResultListBean
package com.qianmo.httprequest.bean; import java.util.List; /** * 服務(wù)端返回帶有List數(shù)據(jù)的通用接收實(shí)體 * Created by wangjitao on 15/12/1. */ public class CommonResultListBean<T> { private String code; private List<T> data; private String message; public String getCode() { return code; } public void setCode(String code) { this.code = code; } public List<T> getData() { return data; } public void setData(List<T> data) { this.data = data; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
ok,現(xiàn)在還是以上面我們登錄的接口為例子開(kāi)始我們的方法調(diào)用,返回的數(shù)據(jù)格式如圖所示
我們創(chuàng)建UserMenu.java類
package com.qianmo.httprequest.bean; import java.util.List; /** * Created by wangjitao on 2016/12/21 0021. * E-Mail:543441727@qq.com * 用戶菜單權(quán)限按鈕 */ public class UserMenu { /** * last_login_time : 2016-12-21 15:40:28 * member_id : 1 * modules : [] * phone : 18900532225 * real_name : 超級(jí)管理員 * role : {"role_id":1,"role_name":"超級(jí)管理員"} * username : superadmin */ private String last_login_time; private int member_id; private String phone; private String real_name; /** * role_id : 1 * role_name : 超級(jí)管理員 */ private RoleBean role; private String username; /** * module_code : 100 * module_id : 1 * module_name : 首頁(yè) * pid : 0 * type : 1 * value : P_index */ private List<ModulesBean> modules; public String getLast_login_time() { return last_login_time; } public void setLast_login_time(String last_login_time) { this.last_login_time = last_login_time; } public int getMember_id() { return member_id; } public void setMember_id(int member_id) { this.member_id = member_id; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getReal_name() { return real_name; } public void setReal_name(String real_name) { this.real_name = real_name; } public RoleBean getRole() { return role; } public void setRole(RoleBean role) { this.role = role; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public List<ModulesBean> getModules() { return modules; } public void setModules(List<ModulesBean> modules) { this.modules = modules; } public static class RoleBean { private int role_id; private String role_name; public int getRole_id() { return role_id; } public void setRole_id(int role_id) { this.role_id = role_id; } public String getRole_name() { return role_name; } public void setRole_name(String role_name) { this.role_name = role_name; } } public static class ModulesBean { private String module_code; private int module_id; private String module_name; private int pid; private int type; private String value; public String getModule_code() { return module_code; } public void setModule_code(String module_code) { this.module_code = module_code; } public int getModule_id() { return module_id; } public void setModule_id(int module_id) { this.module_id = module_id; } public String getModule_name() { return module_name; } public void setModule_name(String module_name) { this.module_name = module_name; } public int getPid() { return pid; } public void setPid(int pid) { this.pid = pid; } public int getType() { return type; } public void setType(int type) { this.type = type; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } } }
所以MainActivity代碼如下:
package com.qianmo.httprequest; import android.os.Environment; import android.os.Handler; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; import com.qianmo.httprequest.bean.CommonResultBean; import com.qianmo.httprequest.bean.UserMenu; import com.qianmo.httprequest.http.IRequestCallBack; import com.qianmo.httprequest.http.IRequestManager; import com.qianmo.httprequest.http.OkHttpClientManager; import com.qianmo.httprequest.http.RequestFactory; import com.qianmo.httprequest.http.ResultCallback; import com.squareup.okhttp.Call; import com.squareup.okhttp.Callback; import com.squareup.okhttp.FormEncodingBuilder; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Request; import com.squareup.okhttp.RequestBody; import com.squareup.okhttp.Response; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; public class MainActivity extends AppCompatActivity implements OnClickListener { private Handler handler; private TextView tv_message; private Button btn_login; private ProgressBar progressBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv_message = (TextView) findViewById(R.id.tv_message); btn_login = (Button) findViewById(R.id.btn_login); progressBar = (ProgressBar) findViewById(R.id.progressBar); handler = new Handler(); btn_login.setOnClickListener(this); } @Override public void onClick(View view) { progressBar.setVisibility(View.VISIBLE); String url = "http://192.168.1.123:8081/api/login"; Map<String, String> params = new HashMap(); params.put("username", "superadmin"); params.put("pwd", "ba3253876aed6bc22d4a6ff53d8406c6ad864195ed144ab5c87621b6c233b548baeae6956df346ec8c17f5ea10f35ee3cbc514797ed7ddd3145464e2a0bab413"); OkHttpClientManager.postAsyn(url, params, new ResultCallback<CommonResultBean<UserMenu>>() { @Override public void onError(Request request, Exception e) { } @Override public void onResponse(CommonResultBean<UserMenu> response) { if (response.getData() != null) { UserMenu userMenu = response.getData(); tv_message.setText(userMenu.getReal_name()); progressBar.setVisibility(View.GONE); } } }); } }
這樣我們就可以簡(jiǎn)單的調(diào)用了,最后看一下我們的效果:
See You Next Time···
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
Android開(kāi)發(fā)判斷一個(gè)app應(yīng)用是否在運(yùn)行的方法詳解
這篇文章主要介紹了Android開(kāi)發(fā)判斷一個(gè)app應(yīng)用是否在運(yùn)行的方法,結(jié)合實(shí)例形式較為詳細(xì)的分析了Android判斷應(yīng)用運(yùn)行狀態(tài)的相關(guān)操作技巧與注意事項(xiàng),需要的朋友可以參考下2017-11-11Android組件間通信--深入理解Intent與IntentFilter
本篇文章是對(duì)Android組件間通信Intent與IntentFilter進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05Android開(kāi)發(fā)之日歷CalendarView用法示例
這篇文章主要介紹了Android開(kāi)發(fā)之日歷CalendarView用法,簡(jiǎn)單分析了日歷CalendarView組件的功能、屬性設(shè)置方法、界面布局、事件監(jiān)聽(tīng)等相關(guān)操作技巧,需要的朋友可以參考下2019-03-03Android實(shí)現(xiàn)粒子中心擴(kuò)散動(dòng)畫(huà)效果
粒子動(dòng)畫(huà)效果相比其他動(dòng)畫(huà)來(lái)說(shuō)是非常復(fù)雜了的,主要涉及三個(gè)方面,粒子初始化、粒子位移、粒子回收等問(wèn)題,本篇將實(shí)現(xiàn)兩種動(dòng)畫(huà)效果,代碼基本相同,只是旋轉(zhuǎn)速度不一樣,需要的朋友可以參考下2024-02-02Android中使用am命令實(shí)現(xiàn)在命令行啟動(dòng)程序詳解
這篇文章主要介紹了Android中使用am命令實(shí)現(xiàn)在命令行啟動(dòng)程序詳解,本文詳細(xì)講解了am命令的語(yǔ)法,然后給出了啟動(dòng)內(nèi)置程序的操作實(shí)例,需要的朋友可以參考下2015-04-04FragmentTabHost FrameLayout實(shí)現(xiàn)底部導(dǎo)航欄
這篇文章主要為大家詳細(xì)介紹了FragmentTabHost和FrameLayout實(shí)現(xiàn)底部導(dǎo)航欄,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03Android Kotlin環(huán)境使用ButterKnife的方法
本篇文章主要介紹了Android Kotlin環(huán)境使用ButterKnife的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03