大家好,不知不觉进行Android的开发工作已经快4年了,一直在网上观摩各位大牛的博客,令我学到了很多,在此我深表感谢,今天是小弟第一次写自己的博客,希望大家能多多指正。
废话不多说了,下面进入正题:
Http的数据交互相信大家熟悉的不能再熟悉了,每一个开发者都需要研究使用的功能,在这里,我写一下自己的一些实现方式:
首先,Http请求常用的大概有GET和POST两种请求方式,到这里,大家应该有个大概的了解,GET一般用于获取/查询资源信息,而POST一般用于更新资源信息。我们从表面上来看一下GET和POPST的区别:
1.GET请求的数据会附在URL之后(就是把数据放置在HTTP协议头中),以?分割URL和传输数据,参数之间以&
相连,如:login.action?name=hyddd&password=idontknow&verify=%E4%BD%A0%E5%A5%BD。
POST把提交的数据则放置在是HTTP包的包体中。
2.首先是"GET"方式提交的数据最多只能是1024字节",因为GET是通过URL提交数据,那么GET可提交的数据量
就跟URL的长度有直接关系了。而实际上,URL不存在参数上限的问题,HTTP协议规范没有对URL长度进行限
制。这个限制是特定的浏览器及服务器对它的限制。IE对URL长度的限制是2083字节(2K+35)。对于其他浏览
器,如FireFox等,理论上没有长度限制,其限制取决于操作系统的支持。【注意这是限制是整个URL长度,
而不仅仅是你的参数值数据长度。】
然后是POST是没有大小限制的,HTTP协议规范也没有进行大小限制,说“POST数据量存在80K/100K的大小限
制”是不准确的,POST数据是没有限制的,起限制作用的是服务器的处理程序的处理能力。
HTTP协议(HyperText Transfer Protocol,超文本传输协议)的实现原理在这里就不在做多赘述了,下面直接进入代码,由于本代码在okhttp的基础上完成整理,代码中注释也写了很多,这里就直接上代码了:
首先我们写一个类HttpAddress,主要存一些接口地址等常量以及各位自定义的一些数据常量等,例:
package com.hs.http;
import java.util.HashMap;
import java.util.Map;
/**
* 存放所有接口地址
* Created by ZM on 2016/7/13 0022.
*/
class HttpAddress {
/**
* post请求类型传入Map
*/
public static final String HttpTypeMap = "Map";
/**
* post请求类型传入Json
*/
public static final String HttpTypeJson = "JSON";
public static final String CodeThird="error_code";
public static final String MsgThird="reason";
public static final String DataThird="data";
public static final String CodeLocal="code";
public static final String MsgLocal="msg";
public static final String DataLocal="data";
/**
* H5域名
*/
public static String URL_H5 = "https://www.xiaomoc.com/indiana-app/";
/**
* 推广H5
*/
public static String URL_H5_PROMPT = URL_H5 + "html/microSite.html";
/**
* 接口地址(第三方接口服务器地址)
*/
public static String URL_HTTP_THRID = "http://v.juhe.cn/";
/**
* 接口地址(我的App服务器地址)
*/
public static String URL_HTTP = "https://www.xiaomoc.com/indiana-app/";
/**
* 图片服务器地址
*/
public static String URL_IMAGE = "http://120.77.13.93/";
/**
* 设置USERID
*/
public static int UserID;
public static int getUserID() {
return UserID;
}
public static void setUserID(int userID) {
UserID = userID;
}
protected static final Map<Integer, String> address = new HashMap();
/*分享Image图片URL*/
public static final String SHAREIMAGE = "http://www.xiaomoc.top/0986e377ef7e996aa077234080630fd1";
private static final String TAG = "HttpAddress";
public static final int NEWS=0;
static {
address.put(NEWS, "app/carnews/list");
}
}
然后,我们来写一个回调的监听接口类:HttpCallbackListener
package com.hs.http;
/**
* Created by ${ZM} on 2016/7/13 0013.
*/
public interface HttpCallbackListener<T> {
/**
* 没有网络时返回
*/
void noNetwork(int code,String msg);
/**
* 未知错误返回
* @param msg 错误信息
*/
void unknownError(int code,String msg);
/**
* 失败时返回
*
* @param code 错误码
* @param msg 错误信息
*/
void failure(int code, String msg);
/**
* 成功时返回
* @param t
*/
void success(int id,T t);
}
第三步,建立我们的请求方法,这里的例子根据我自己项目中用的,首先创建请求体,然后通过一些接口回调完成数据的传输,并在成功时缓存了获取到的数据,方便在下一次因为某些原因获取失败时,直接返回上一次缓存的数据,然后获取里面包含了Get,Post(这里因为项目需要,写了两种请求体的生成方式),可能有些地方对于大家来说是多余的,以下就不说了,直接上全部代码了,大家仅仅做个参考:
HttpRequest:
package com.hs.http;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import com.squareup.okhttp.Call;
import com.squareup.okhttp.Callback;
import com.squareup.okhttp.FormEncodingBuilder;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.MultipartBuilder;
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.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import cn.ljguo.security.AESAndroid;
import cn.ljguo.security.MD5;
import demo.hs.util.NetWorkUtil;
/**
* Created by ZM on 2016/7/13 0013.
*/
abstract class HttpRequest extends HttpAddress {
private final static String TAG = "HTTP";
// md5加密(本App中没用到)
// if (BuildConfig.IS_HTTP_ENCRYPTED) {
// json = MobileKit.encryptMobileText(json.toString());
// }
// md5解密(本App中没用到)
// if (BuildConfig.IS_HTTP_ENCRYPTED) {
// content = MobileKit.decryptMobileText(content);
// Log.e(TAG, "获取服务器加密后的数据=[" + content + "]");
// } else {
// Log.e(TAG, "获取到数据=[" + content + "]");
// }
/***
* POST方式传参请求
*
* @param id 接口Id
* @param isThrid true--第三方接口服务器 false--自己App后台提供的服务器
* @param httpType HttpTypeMap--传入map类型 HttpTypeJson--传入json类型
* @param result 返回的bean集合
* @param context 上下文
* @param builder httpType为HttpTypeMap时,传入Builder对象,否则传NUll
* @param json httpType为HttpTypeJson时,传入String对象,否则传NUll
* @param callback 回调接口
*/
protected void requestPost(final int id, final boolean isThrid, String httpType, final IHttpResult result, final Context context, FormEncodingBuilder builder, final String json, final HttpCallbackListener callback) {
String url = null;
if (isThrid) {
url = URL_HTTP_THRID + HttpAddress.address.get(id);
} else {
url = URL_HTTP + HttpAddress.address.get(id);
}
if (!NetWorkUtil.isNetworkAvailable(context)) {
callback.noNetwork(id, "请检查您的网络连接");
getCatch(isThrid, id, result, context, callback);
return;
}
OkHttpClient client = new OkHttpClient();
client.setConnectTimeout(10, TimeUnit.SECONDS);
client.setWriteTimeout(10, TimeUnit.SECONDS);
client.setReadTimeout(30, TimeUnit.SECONDS);
Request request = null;
switch (httpType) {
case HttpTypeMap:
Log.e(TAG, "请求的接口=" + url + "传入的参数=" + builder.toString());
request = new Request.Builder().url(url).post(builder.build()).build();
break;
case HttpTypeJson:
Log.e(TAG, "请求的接口=" + url + "传入的参数=" + json.toString());
final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
request = new Request.Builder().url(url).post(RequestBody.create(JSON, json.toString())).build();
break;
}
CallHttp(client, request, context, id, isThrid, true, result, callback);
}
/***
* Get方式请求数据
*
* @param id 接口Id
* @param isThrid true--第三方接口服务器 false--自己App后台提供的服务器
* @param result 返回的bean集合
* @param context 上下文
* @param json 传入String对象
* @param callback 回调接口
*/
protected void requestGet(final int id, final boolean isThrid, final IHttpResult result, final Context context, final String json, final HttpCallbackListener callback) {
String url = null;
if (isThrid) {
url = URL_HTTP_THRID + HttpAddress.address.get(id) + json;
} else {
url = URL_HTTP + HttpAddress.address.get(id) + json;
}
if (!NetWorkUtil.isNetworkAvailable(context)) {
callback.noNetwork(id, "请检查您的网络连接");
getCatch(isThrid, id, result, context, callback);
return;
}
Log.e(TAG, "请求的接口=" + url);
OkHttpClient client = new OkHttpClient();
client.setConnectTimeout(10, TimeUnit.SECONDS);
client.setWriteTimeout(10, TimeUnit.SECONDS);
client.setReadTimeout(30, TimeUnit.SECONDS);
final Request request = new Request.Builder().url(url).get().build();
CallHttp(client, request, context, id, isThrid, true, result, callback);
}
/***
* 上传Image图片到服务器
* @param id 接口Id
* @param result 返回的bean集合
* @param context 上下文
* @param map 传入的Map参数对象
* @param files 传入的文件对象
* @param callback 回调接口
*/
protected void requestPostImage(final int id, final IHttpResult result, final Context context, final HashMap<String, String> map, List<File> files, final HttpCallbackListener callback) {
final String url = URL_HTTP + HttpAddress.address.get(id);
if (!NetWorkUtil.isNetworkAvailable(context)) {
callback.noNetwork(id, "请检查您的网络连接");
return;
}
Log.d(TAG, "请求的接口=" + url);
final MediaType MEDIA_TYPE_PNG = MediaType.parse("multipart/form-data");
//创建OkHttpClient实例
final OkHttpClient client = new OkHttpClient();
MultipartBuilder builder = new MultipartBuilder().type(MultipartBuilder.FORM);
//遍历map中所有参数到builder
if (map != null && map.size() != 0) {
for (String key : map.keySet()) {
builder.addFormDataPart(key, map.get(key));
}
}
if (files != null && files.size() != 0) {
//遍历paths中所有图片绝对路径到builder,并约定key如“upload”作为后台接受多张图片的key
for (File file : files) {
builder.addFormDataPart(UUID.randomUUID().toString(), file.getName(), RequestBody.create(MEDIA_TYPE_PNG, file));
}
}
//构建请求体
RequestBody requestBody = builder.build();
//构建请求
Request request = new Request.Builder()
.url(url)//地址
.post(requestBody)//添加请求体
.build();
CallHttp(client, request, context, id, false, false, result, callback);
}
/***
* 构建请求以及获取返回数据
*
* @param client
* @param request
* @param context
* @param id
* @param isThrid
* @param isCatch
* @param result
* @param callback
*/
public void CallHttp(OkHttpClient client, Request request, final Context context, final int id, final boolean isThrid, final boolean isCatch, final IHttpResult result, final HttpCallbackListener callback) {
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Request request, final IOException e) {
Log.e(TAG, "request=" + request + " IOException=" + e);
if (isCatch) {
getCatch(isThrid, id, result, context, callback);
}
unknowError(context, id, e.getMessage(), callback);
}
@Override
public void onResponse(final Response response) throws IOException {
if (response.code() == 200) {
String content = response.body().string();
final String _content = content;
Log.d(TAG, "获取到数据=[" + content + "]");
if (isCatch) {
setCatch(context, content, id);
}
getResultSuccess(context, isThrid, id, result, _content, callback);
} else {
if (isCatch) {
Log.e(TAG, "请求服务器出错取缓存=[" + response.body().string() + "]");
getCatch(isThrid, id, result, context, callback);
} else {
Log.e(TAG, "请求服务器出错=[" + response.body().string() + "]");
}
unknowError(context, id, response.message(), callback);
}
}
});
}
/***
* 写入缓存
*
* @param context
* @param content
* @param id
*/
protected void setCatch(Context context, String content, int id) {
try {
/*需要缓存数据时,加密后保存在本地缓存*/
if (BuildConfig.IS_HTTP_CACHE) {
ACache cache = ACache.get(context);
content = AESAndroid.encrypt(content, BuildConfig.HTTP_CACHE_PASSWORD);
Log.e(TAG, "写入缓存的内容=" + content);
cache.put(MD5.MD5Encode(HttpAddress.address.get(id)), content);
}
} catch (Exception e) {
Log.e(TAG, "写入缓存失败");
}
}
/***
* 获取缓存数据
*
* @param isThrid
* @param id
* @param result
* @param context
* @param callback
*/
protected void getCatch(boolean isThrid, int id, IHttpResult result, Context context, HttpCallbackListener callback) {
if (isThrid) {
getCache(id, result, context, HttpAddress.address.get(id), CodeThird, MsgThird, DataThird, callback);
} else {
getCache(id, result, context, HttpAddress.address.get(id), CodeLocal, MsgLocal, DataLocal, callback);
}
}
/***
* 获取数据成功
*
* @param context
* @param isThrid
* @param id
* @param result
* @param _content
* @param callback
*/
protected void getResultSuccess(final Context context, final boolean isThrid, final int id, final IHttpResult result, final String _content, final HttpCallbackListener callback) {
if (context instanceof Activity) {
((Activity) context).runOnUiThread(new Runnable() {
@Override
public void run() {
if (isThrid) {
result(id, result, context, _content, CodeThird, MsgThird, DataThird, callback);
} else {
result(id, result, context, _content, CodeLocal, MsgLocal, DataLocal, callback);
}
}
});
} else {
if (isThrid) {
result(id, result, context, _content, CodeThird, MsgThird, DataThird, callback);
} else {
result(id, result, context, _content, CodeLocal, MsgLocal, DataLocal, callback);
}
}
}
/***
* 当错误时返回错误信息
*
* @param context
* @param id
* @param msg
* @param callback
*/
protected void unknowError(Context context, final int id, final String msg, final HttpCallbackListener callback) {
if (context instanceof Activity) {
((Activity) context).runOnUiThread(new Runnable() {
@Override
public void run() {
callback.unknownError(id, msg);
}
});
} else {
callback.unknownError(id, msg);
}
}
/***
* Http请求失败时获取之前成功时的缓存信息(通过解密之前保存的缓存数据获取)
*
* @param id
* @param result
* @param context
* @param key
* @param c
* @param m
* @param d
* @param callback
*/
private void getCache(int id, IHttpResult result, Context context, String key, String c, String m, String d, HttpCallbackListener callback) {
try {
if (BuildConfig.IS_HTTP_CACHE) {
ACache cache = ACache.get(context);
String content = cache.getAsString(MD5.MD5Encode(key));
if (content != null && !content.isEmpty()) {
content = AESAndroid.decrypt(content, BuildConfig.HTTP_CACHE_PASSWORD);
Log.e(TAG, "读取缓存数据=" + content);
result(id, result, context, content, c, m, d, callback);
}
}
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
}
protected abstract void result(Integer id, IHttpResult result, Context context, String json, String code, String msg, String data, HttpCallbackListener callback);
}
HttpResult:
package com.hs.http;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import org.json.JSONException;
import org.json.JSONObject;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
/**
* Created by ZM on 2016/7/13 0013.
*/
public class HttpResult extends HttpRequest {
@Override
protected void result(Integer id, IHttpResult result, Context context, String json,String c,String m,String d, HttpCallbackListener callback) {
try {
JSONObject jsonObject = new JSONObject(json);
int code = jsonObject.getInt(c);
if (code == 200) {
HttpResultHandler handler = new HttpResultHandler(result);
IHttpResult proxy = (IHttpResult) Proxy.newProxyInstance(result.getClass().getClassLoader(), result.getClass().getInterfaces(), handler);
proxy.result(context, id, jsonObject, callback);
} else {
String msg="";
msg = jsonObject.getString(m);
if(TextUtils.isEmpty(msg)){
msg=jsonObject.getString(d);
}
callback.failure(id, msg);
}
} catch (JSONException e) {
callback.unknownError(id,e.getMessage());
}
}
protected class StringConverter implements JsonSerializer<String>,
JsonDeserializer<String> {
public JsonElement serialize(String src, Type typeOfSrc,
JsonSerializationContext context) {
if (src == null) {
return new JsonPrimitive("");
} else {
return new JsonPrimitive(src.toString());
}
}
public String deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context)
throws JsonParseException {
return json.getAsJsonPrimitive().getAsString();
}
}
}
BaseHttpResult:
package com.hs.http;
import android.content.Context;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.json.JSONObject;
import java.util.List;
/**
* Created by ZM on 2016/7/13 0013.
*/
public class BaseHttpResult extends HttpResult{
private final static String TAG="BaseHttpResult";
protected class ResultList<T> implements IHttpResult<T> {
private String mTag;
private Class mClass;
public ResultList(String tag,Class c){
mTag=tag;
this.mClass=c;
}
@Override
public void result(Context context, Integer id, JSONObject jsonObject, HttpCallbackListener callback) {
try {
Gson gson = new Gson();
String json="";
if(mTag!=null&&!mTag.equals("")){
json=jsonObject.get(mTag).toString();
}else{
json=jsonObject.toString();
}
List<T> playDaysOfMonthList = gson.fromJson(json,new TypeToken<List<T>>(){}.getType());
callback.success(id, playDaysOfMonthList);
} catch (Exception e) {
callback.unknownError(id,e.getMessage());
}
}
}
protected class ResultBean<T> implements IHttpResult{
private Class c;
private String mTag;
public ResultBean(Class c){
this.c=c;
}
public ResultBean(Class c,String tag){
this.c=c;
this.mTag=tag;
}
@Override
public void result(Context context, Integer id, JSONObject jsonObject, HttpCallbackListener callback) {
try {
Log.d(TAG,"t="+c);
String json="";
if(mTag!=null&&!mTag.equals("")){
json=jsonObject.get(mTag).toString();
}else{
json=jsonObject.toString();
}
T t = (T) new Gson().fromJson(json,c);
callback.success(id, t);
} catch (Exception e) {
callback.unknownError(id,e.getMessage());
}
}
}
protected class ResultMap implements IHttpResult{
@Override
public void result(Context context, Integer id, JSONObject jsonObject, HttpCallbackListener callback) {
try {
callback.success(id, JsonToMap.toMap(jsonObject.toString()));
} catch (Exception e) {
callback.unknownError(id,e.getMessage());
}
}
}
protected class ResultSuccess implements IHttpResult{
@Override
public void result(Context context, Integer id, JSONObject jsonObject, HttpCallbackListener callback) {
try {
callback.success(id,jsonObject);
} catch (Exception e) {
callback.unknownError(id,e.getMessage());
}
}
}
}
HsHttpResult(这里写自己需要返回的内容):
package com.hs.http;
import android.content.Context;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.hs.data.TestBean;
import org.json.JSONObject;
import java.util.List;
/**
* Created by ZM on 2016/7/13 0013.
*/
public class HsHttpResult extends BaseHttpResult {
/***
* 获取新闻列表json返回
*/
protected class getNewsList implements IHttpResult {
@Override
public void result(Context context, Integer id, JSONObject jsonObject, HttpCallbackListener callback) {
try {
List<TestBean> info=new Gson().fromJson(jsonObject.getString("data"),new TypeToken<List<TestBean>>() {
}.getType());
callback.success(id, info);
} catch (Exception e) {
callback.unknownError(id,e.getMessage());
}
}
}
}
HttpResultHandler:
package com.hs.http;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* Created by ZM on 2016/7/13 0013.
*/
public class HttpResultHandler implements InvocationHandler {
private Object mObject;
protected HttpResultHandler(Object object) {
super();
this.mObject = object;
}
public Object invoke(Object proxy, Method method, Object... args) throws Throwable {
Object result = null;
result = method.invoke(mObject, args);
return result;
}
}
IHttpResult:
package com.hs.http;
import android.content.Context;
import org.json.JSONObject;
/**
* Created by ZM on 2016/7/13 0013.
*/
public interface IHttpResult<T> {
void result(Context context, Integer id, JSONObject jsonObject, HttpCallbackListener callback);
}
JsonToMap:
package com.hs.http;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.util.List;
import java.util.Map;
/**
* Created by ZM on 2016/7/13 0013.
*/
public class JsonToMap {
/**
* 根据json字符串返回Map对象
*
* @param json
* @return
*/
protected static Map<String, Object> toMap(String json) {
return new Gson().fromJson(json, new TypeToken<Map<String, Object>>() {
}.getType());
}
protected static List<Map<String,Object>> toList(String json){
return new Gson().fromJson(json, new TypeToken<List<Map<String, Object>>>() {
}.getType());
}
}
最后 Http:
package com.hs.http;
import android.content.Context;
/**
* 存放所有接口请求
* Created by ZM on 2016/7/13 0013.
*/
public class Http extends HsHttpResult {
/***
* 获取新闻列表
*
* @param context
* @param callback
*/
public void getNewsList(Context context, int currentPage, int numPerPage, HttpCallbackListener callback) {
requestGet(NEWS,false,new getNewsList(),context,"?currentPage=" + currentPage + "&numPerPage="+numPerPage,callback);
}
// /***
// * 上传头像
// *
// * @param context
// * @param files
// * @param callback
// */
// public void uploadHeader(Context context, String userid, List<File> files, HttpCallbackListener callback) {
// HashMap<String,String> map=new HashMap<>();
// map.put("userId", userid);
// request(UPLOADHEADER,new loginResult(),context,map,files,callback);
// }
}
使用方式示例 TestActivity:
package com.hs.qianshubao.wealth.base;
import android.app.Activity;
import android.os.Bundle;
import com.hs.data.TestBean;
import com.hs.http.Http;
import com.hs.http.HttpCallbackListener;
import com.hs.qianshubao.wealth.R;
import java.util.List;
/**
* Created by ZM on 2017/4/18 0018.
*/
public class TestActivity extends Activity implements HttpCallbackListener {
public static String TAG="TestActivity";
Http http;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
http=new Http();
http.getNewsList(this,1,10,this);
}
@Override
public void noNetwork(int code, String msg) {
/*这里处理没网的情况 code-请求的接口ID ,例:NEWS ,msg----说明语句*/
}
@Override
public void unknownError(int code, String msg) {
/*这里处理出现位置错误的情况 code-请求的接口ID ,例:NEWS ,msg----错误提示*/
}
@Override
public void failure(int code, String msg) {
/*这里处理出现一些服务器错误的情况 code-请求的接口ID ,例:NEWS ,msg----错误提示*/
}
@Override
public void success(int id, Object o) {
/*这里处理请求成功后的情况 id-请求的接口ID ,例:NEWS ,o----在HsHttpResult获取的返回内容 */
List<TestBean> mList= (List<TestBean>) o;
Log.e(TAG,"====="+mList.toString());
}
}
今天就到这里了,欢迎各位大牛批评指正,感谢!
下载链接:http://download.youkuaiyun.com/detail/zhang6511828/9818075