網上有很多OkHttp使用的教程,而我今天要給大家分享的是我自己對OkHttp的使用并且做了簡單的封裝,希望能給你們帶來幫助,話不多說了下面直接上干貨了(我使用的是Android Studio)。
官方的文檔
OkHttp官網地址:http://square.github.io/okhttp/
OkHttp GitHub地址:https://github.com/square/okhttp
OKHttp的使用
Android Studio用戶在 Gradle中添加:
compile'com.squareup.okhttp3:okhttp:3.8.1'
compile 'com.squareup.okio:okio:1.13.0'
Eclipse的用戶,添加依賴包即可,Jar包下載地址: okhttp3_Jar okio_Jar
干貨來了(直接上代碼)
1.請求地址配置
/**
* 網絡訪問地址定義
* @author zcq
* Created by 2016/4/25.
*/
public class ApiConfig {
public final static String API_BSAE = "http://192.168.1.118/help/";
}
2.接口錯誤定義
/**
* 接口錯誤定義
* @author zcq
* Created by 2017/4/25.
*/
public enum ErrorCode {
/**
* 無錯誤
*/
None,
/**
* 網絡錯誤
*/
NetworkError,
/**
* 服務器錯誤
*/
ServerError,
/**
* 數據錯誤
*/
DataError
}
3.數據接口監聽器
/**
* 數據偵聽器接口定義,用于向接口傳遞單條數據
* @author zcq
* Created by 2016/4/25.
*/
public interface OnDataListener<T> extends OnErrorListener{
/**
* 向接口傳遞單條數據
* @param isSuccess 接口調用是否成功
* @param data 待傳遞的單條數據
* @param errorCode 接口調用失敗時錯誤碼
* @param errorReason 接口調用失敗時的原因
*/
void onData(boolean isSuccess, T data, int errorCode, String errorReason);
}
/**
* 數據偵聽器接口定義,用于向接口傳遞單條數據
* @author zcq
* Created by 2016/4/25.
*/
public interface OnListListener<T> extends OnErrorListener{
/**
* 向接口傳遞多條數據
* @param isSuccess 接口調用是否成功
* @param data 待傳遞的多條數據
* @param errorCode 接口調用失敗時錯誤碼
* @param errorReason 接口調用失敗時的原因
*/
void onList(boolean isSuccess, List<T> data, int errorCode, String errorReason);
}
/**
* @author zcq
* Created by 2016/4/25.
*/
public interface OnImageListener {
void onImage(int position, String url, Bitmap bitmap);
}
/**
* 錯誤偵聽器接口定義,用于向接口傳遞錯誤信息
* @author zcq
* Created by 2016/4/25.
*/
public interface OnErrorListener {
/**
* 向接口傳遞錯誤信息
* @param code 待傳遞的錯誤信息
*/
void onError(ErrorCode code);
}
4.與服務器通訊接口類定義
/**
* 與服務器通訊接口類定義
* @author zcq
* Created by 2016/4/25.
*/
public class HttpHelper {
private final static boolean DEBUG = true;
private final static String TAG = "help/HttpHelper";
protected final static int MESSAGE_DATA = 0;
protected final static int MESSAGE_ERROR = 1;
/**
* 接收到網絡數據
* @param event 事件的標識
* @param response 所接收到的數據
*/
protected void onData(int event, String response){
}
/**
* 接收到網絡錯誤
* @param event 事件的標識
* @param code 所接收到的錯誤碼
*/
protected void onError(int event, ErrorCode code){
}
static class UIHandler extends Handler {
private final WeakReference<HttpHelper> ref;
UIHandler(HttpHelper act) {
this.ref = new WeakReference<>(act);
}
@Override
public void handleMessage(Message msg) {
HttpHelper act = ref.get();
if (msg.what == MESSAGE_DATA) {
act.onData(msg.arg1, msg.obj != null ? msg.obj.toString() : null);
} else if (msg.what == MESSAGE_ERROR) {
act.onError(msg.arg1, (ErrorCode) msg.obj);
} else {
super.handleMessage(msg);
}
}
}
private final UIHandler mHandler = new UIHandler(this);
/**
* 開始異步訪問網絡接口
* @param event 事件編號
* @param url 接口地址
* @param params 待提交的參數
*/
protected synchronized void beginRequest(final int event, final String url, final Map<String, String> params){
new Thread(new Runnable() {
@Override
public void run() {
OkHttpClient client = new OkHttpClient();
FormBody.Builder formBodayBuilder = new FormBody.Builder();
//參數處理
if (params != null) {
for (String param : params.keySet()) {
String value = params.get(param);
if (value != null) {
formBodayBuilder.add(param, value);
}
}
}
//設置發出的 request
Request post = new Request.Builder()
.url(url) //請求的地址
.post(formBodayBuilder.build()) //請求的參數
.tag(event) //請求標識
.build();
try {
//獲取 response
Response response = client.newCall(post).execute();
if (response.isSuccessful()) {
String res = response.body().string();
// Log.i("----API請求返回值----","----***************---res:"+res);
if (res != null) {
mHandler.obtainMessage(MESSAGE_DATA, event, 0, res).sendToTarget();
} else {
mHandler.obtainMessage(MESSAGE_ERROR, event, 0, ErrorCode.ServerError).sendToTarget();
}
} else {
if (DEBUG) {
String res = response.body().toString();
if (res != null) {
Log.d(TAG, res);
}
}
mHandler.obtainMessage(MESSAGE_ERROR, event, 0, ErrorCode.ServerError).sendToTarget();
}
} catch (IOException e) {
mHandler.obtainMessage(MESSAGE_ERROR, event, 0, ErrorCode.NetworkError).sendToTarget();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
/**
* 開始異步上傳文件
* @param event 事件編號
* @param url 接口地址
* @param params 待提交的參數
*filesam files 待上傳的文件
*/
protected synchronized void beginUpload(final int event, final String url,
final Map<String, String> params,
final Map<String, String> files) {
new Thread(new Runnable() {
@Override
public synchronized void run() {
OkHttpClient client = new OkHttpClient();
//以表單方式上傳圖片文件
MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
//非文件參數處理
if (params != null) {
for (String param : params.keySet()) {
String value = params.get(param);
if (value != null) {
builder.addFormDataPart(param, value);
}
}
}
//文件參數處理 TODO: MediaType 可提出作為參數
MediaType MEDIA_TYPE_PNG = MediaType.parse("image/png");
int i = 0;
if(files != null){
for (String key : files.keySet()){
File file = new File(files.get(key));
if(file != null){
builder.addFormDataPart("file"+i, file.getName(), RequestBody.create(MEDIA_TYPE_PNG, file));
}
i++;
}
}
MultipartBody requestBody = builder.build();
//請求
Request post = new Request.Builder()
.url(url) //請求的地址
.post(requestBody) //請求的參數
.tag(event) //請求標識
.build();
try {
//獲取 response
Response response = client.newCall(post).execute();
if (response.isSuccessful()) {
String res = response.body().string();
if (res != null) {
mHandler.obtainMessage(MESSAGE_DATA, event, 0, res).sendToTarget();
} else {
mHandler.obtainMessage(MESSAGE_ERROR, event, 0, ErrorCode.ServerError).sendToTarget();
}
} else {
if (DEBUG) {
String res = response.body().toString();
if (res != null) {
Log.d(TAG, res);
}
}
mHandler.obtainMessage(MESSAGE_ERROR, event, 0, ErrorCode.ServerError).sendToTarget();
}
} catch (IOException e) {
mHandler.obtainMessage(MESSAGE_ERROR, event, 0, ErrorCode.NetworkError).sendToTarget();
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
/**
* 開始異步訪問網絡接口
* @param event 事件編號
* @param url 接口地址
*/
protected synchronized void beginRequest(int event, String url) {
beginRequest(event, url, null);
}
}
5.返回的 JSON 數據進行解析的幫助類
/**
* 對 HTTP 返回的 JSON 數據進行解析的幫助類
* @author zcq
* Created by 2016/4/25.
*/
public class JsonHttpHelper extends HttpHelper{
private final static boolean DEBUG = true;
private final static String TAG = "help/HttpHelper";
/**
* 接收到網絡數據
*
* @param event 事件的標識
* @param response 所接收到的數據
*/
@Override
protected void onData(int event, String response) {
try {
// 開始解析數據
JSONObject jsonObject = new JSONObject(response);
JsonResult jsonResult = new JsonResult();
jsonResult.isSuccess = jsonObject.optBoolean("IsSuccess");
if (jsonResult.isSuccess) {
jsonResult.returnValue = jsonObject.optString("ReturnValue");
} else {
jsonResult.errorCode = jsonObject.optInt("ErrorCode");
jsonResult.errorReason = jsonObject.optString("ErrorMessage");
}
onResult(event, jsonResult);
} catch (JSONException e) {
onError(event, ErrorCode.DataError);
}
}
/**
* 接口調用完成時解析后的數據
*
* @param event 事件的標識
* @param result 解析后的數據
*/
protected void onResult(int event, JsonResult result) {
}
/**
* 將解析后的數據交給指定偵聽器進行處理
*
* @param result 待處理的數據
* @param cls 返回值對應的類
* @param <T> 返回值對應的數據類型
* @param listener 指定的偵聽器
*/
@SuppressWarnings("unchecked")
protected <T> void handleData(@NonNull JsonResult result, @NonNull Class<T> cls, @Nullable OnErrorListener listener) {
// 檢查偵聽器有無注冊
if (listener == null) {
if (DEBUG) {
Log.d(TAG, "the listener not used.");
}
return;
}
// 接口返回失敗時不解析返回值
if (!result.isSuccess) {
if (listener instanceof OnDataListener) {
((OnDataListener<T>) listener).onData(false, null, result.errorCode, result.errorReason);
} else if (listener instanceof OnListListener) {
((OnListListener<T>) listener).onList(false, null, result.errorCode, result.errorReason);
}
return;
}
// 將返回值字符串解析成對象
ObjectMapper objectMapper = new ObjectMapper();
try {
if (listener instanceof OnDataListener) {
// 返回的數據為單個對象
T returnValue;
if (cls.getSimpleName().equals("String")) {
returnValue = (T) result.returnValue;
} else {
returnValue = objectMapper.readValue(result.returnValue, cls);
}
((OnDataListener<T>) listener).onData(true, returnValue, 0, null);
} else if (listener instanceof OnListListener) {
// 返回的數據為列表數據
List<T> returnValue = objectMapper.readValue(
result.returnValue, TypeFactory.defaultInstance()
.constructCollectionType(List.class, cls));
((OnListListener<T>) listener).onList(true, returnValue, 0, null);
}
} catch (IOException e) {
listener.onError(ErrorCode.DataError);
}
}
}
6.請求返回值JSON格式定義
/**
* 網絡請求返回值 JSON 格式定義
* @author zcq
* Created by 2016/4/25.
*/
public class JsonResult {
/**
* 判斷接口是否調用成功
*/
public boolean isSuccess;
/**
* 接口返回值
*/
public String returnValue;
/**
* 接口返回錯誤時的Code
*/
public int errorCode;
/**
* 接口返回的錯誤信息
*/
public String errorReason;
}
以上就是我使用OkHttp自定義的封裝請求相關的所有代碼了,下面則是使用的測試樣例
- TestApi定義
/**
* @author zcq
* Created by 2016/4/26.
*/
public class TestApi extends JsonHttpHelper{
//事件定義
private final static int EVENT_HOST_API_BASE = 1000;
private final static int EVENT_GET_PERSONAGE_LIST = EVENT_HOST_API_BASE + 1;
//訪問地址的定義
private final static String HOST_SITE = ApiConfig.API_BSAE;
//接口路徑
private final static String URL_GET_PERSONAGE_LIST = HOST_SITE + "mobile/star/getDataLs"; //獲取數據列表接口
/**
* 接口調用完成時解析后的數據
* @param event 事件的標識
* @param result 解析后的數據
*/
@Override
protected void onResult(int event, JsonResult result) {
switch (event) {
case EVENT_GET_PERSONAGE_LIST:
handleData(result, Personage.class, mOnGetPersonageLsListener);
break;
}
}
/**
* 接收到網絡錯誤
* @param event 事件的標識
* @param code 所接收到的錯誤碼
*/
@Override
protected void onError(int event, ErrorCode code) {
switch (event) {
case EVENT_GET_PERSONAGE_LIST:
if(mOnGetPersonageLsListener != null){
mOnGetPersonageLsListener.onError(code);
}
break;
}
}
/*********************** 獲取List<Entity> **********************/
//獲取數據列表接口
private OnListListener<Personage> mOnGetPersonageLsListener;
/**
* 獲取數據列表接口
* @param listener 待設置的偵聽器
*/
public void setOnGetPersonageLsListener(OnListListener<Personage> listener){
this.mOnGetPersonageLsListener = listener;
}
/**
* 獲取數據列表接口
* @param pageNum 當前頁
* @param pageSize 分頁數
*/
public void getPersonageLs(int pageNum, int pageSize){
Map<String, String> params = new HashMap<String, String>();
params.put("pageNum", String.valueOf(pageNum));
params.put("pageSize", String.valueOf(pageSize));
params.put("channel_num","android");
beginRequest(EVENT_GET_PERSONAGE_LIST, URL_GET_PERSONAGE_LIST, params);
}
/*********************** 獲取Entity String Boolean**********************/
//使用 OnDataListener<Entity> OnDataListener<String> OnDataListener<Boolean>
//配置 handleData(result, Entity.class, mOnListener);
//配置 handleData(result, Boolean.class, mOnListener);
//配置 handleData(result, String.class, mOnListener);
}
- 測試Activity
public class TestAct extends Activity{
private TestApi mApi;
private TextView text;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.new_ui_test_api);
mApi = new TestApi();
text = (TextView)findViewById(R.id.text);
//Button按鈕
findViewById(R.id.list_btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mApi.getPersonageLs(0, 2);
}
});
//設置偵聽器
mApi.setOnGetPersonageLsListener(new OnListListener<Personage>() {
@Override
public void onList(boolean isSuccess, List<Personage> data, int errorCode, String errorReason) {
if(isSuccess){
text.setText(data.get(0).desc);
Toast.makeText(TestAct.this, "List_成功!", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(TestAct.this, "List_失??!", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onError(ErrorCode code) {
if(code.equals(ErrorCode.DataError)){
Toast.makeText(TestAct.this, "數據錯誤!", Toast.LENGTH_SHORT).show();
}else if(code.equals(ErrorCode.NetworkError)){
Toast.makeText(TestAct.this, "網絡錯誤!", Toast.LENGTH_SHORT).show();
}else if(code.equals(ErrorCode.ServerError)){
Toast.makeText(TestAct.this, "服務器錯誤!", Toast.LENGTH_SHORT).show();
}
}
});
}
}
- 數據實體類 bean
/**
* 實體類
* @author zcq
* Created by 2016/4/26.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class Personage implements Serializable {
@JsonProperty("column_id")
public String id;
@JsonProperty("column_name")
public String name;
@JsonProperty("column_context")
public String context;
@JsonProperty("column_desc")
public String desc;
@JsonProperty("column_icon")
public String imgUrl;
@JsonProperty("create_time")
public String create_time;
}
最后附上API接口模板_樣例說明
Paste_Image.png
- 返回值樣例(標準Json格式)
//返回值為Boolean樣例:
{
"IsSuccess":true,
"ReturnValue":true,
"ErrorMessage":"",
"ErrorCode":0
}
//返回值為String樣例:
{
"IsSuccess":true,
"ReturnValue": "http://139.196.192.92/images/info/20160303/20160303110822_head_846141.jpg",
"ErrorMessage":"",
"ErrorCode":0
}
//返回值為List<Entity>樣例:
{
"IsSuccess":true,
"ReturnValue":"[{
"commentId":239,
"infoId":6375,
"authorId":40,
"author":"青牙",
"head_img_url":"http://139.196.192.92/images/info/20160303/20160303110822_head_846141.jpg",
"comment_content":"感覺可憐可憐",
"time":"2017-04-26"
},
{
"commentId":238,
"infoId":6375,
"authorId":40,
"author":"青牙",
"head_img_url":"http://139.196.192.92/images/info/20160303/20160303110822_head_846141.jpg",
"comment_content":"過來看看",
"time":"2017-04-26"}]"
"ErrorMessage":"",
"ErrorCode":0
}
//返回值為Entity樣例:
{
"IsSuccess":true,
"ReturnValue":"{
"infoId":6375,
"title":"評《錦繡未央》抄襲:放任大\"IP\"抄襲只會劣幣驅逐良幣",
"comment_count":4,
"time":"2017-04-26",
"is_like":"0",
"token":"827885c0-db46-4234-a22b-af7aae0f31d9",
"shareUrl":"http://139.196.192.92/cbtt/admin/info/viewDetailOnPhone?infoId=6375",
}",
"ErrorMessage":"",
"ErrorCode":0
}