吐槽
我们做移动开发的,网络操作可以说是最最常用的技术了,而在网络操作中http又是一块最常见的的方式,返回json的http请求可以说是我们日常最长干的活。你一般用什么框架去请求http呢?Volley?OkHttp? 不管哪种方式用起来是不是还是不那么的方便,我们依然要写大量的请求、解析、返回的代码。好,这篇博客,不是让你替换掉你最常用的那个网络框架,而是在你熟悉的框架之上二次封装!目的就是为了解放你的时间,让网络操作更简单、漂亮。
需求
虽然现在我们有诸如Volley、OkHttp等很好的框架使用,但是你是不是还感觉这部分还是那么的麻烦?你是不是想让每次请求到解析出来几行代码就可以搞定?
下面的两种方式你更喜欢哪种?
MultipartBuilder builder = new MultipartBuilder()
.type(MultipartBuilder.FORM);
...
builder.addPart(Headers.of("Content-Disposition",
"form-data; name=\""+ key +"\""),
RequestBody.create(null, map.get(key)));
...
Request request = new Request.Builder()
.url(url).post(builder.build()).build();
call(request, parser, callback);
RequestParams params = new RequestParams("name", "loader");
params.add("age", 18).add("city", "jinan");
Net.post("http://192.168.3.116/", params, new CommParser<User>("user") {
},
new Net.Callback<User>() {
@Override
public void callback(Result<User> result) {
if(result.getStatus() == Result.SUCCESS) {
User user = result.getResult();
mTextView.setText(user.getName());
...
}else {
mTextView.setText(result.getMsg());
}
}
});
显然第二种方式是我们想要的,有了需求,那我们就得考虑封装了,我在不断尝试以后,终于完成了这种优雅方式的框架的一个小封装,哦,给了它一个特别骚的名字-AndNet,AndNet不仅仅具备上面的便捷功能,它还允许我们随时任意更换我们使用的底层网络请求框架,而不需要改动我们的业务逻辑代码,这一点太棒了!哪天Volley不再适合我们了,我们可以直接切换到OkHttp,而我们的业务代码不需要任何的改变,兴奋ing,下面就让我们开始尝试使用AndNet吧。
准备工作
AndNet默认的网络请求框架是使用的OkHttp,所以你需要在你的项目中添加一下两个依赖:
compile ‘com.squareup.okhttp:okhttp:2.0.0‘
compile ‘com.squareup.okio:okio:1.5.0‘
接下来,我们需要自定义一个Application,在它的onCreate中添加一行代码,
Net.init(new OkHttpStack());
现在我们就指定使用默认的网络请求框架OkHttp,当然如果我们想切换框架,也是在这里做。
自定义parser
在我们开始使用之前,还需要做一件事就是根据你们项目使用的json格式,定义需要的json的parser类,parser部分我是很想写到框架里面的,不过那样灵活性就差了,所以这里还是需要我们在自己的项目里写自己的parser。
假如现在我们json的格式如下,
{
success: true,
message: "",
user: - {
age: "18",
name: "loader",
city: "jinan"
}
}
这种格式在我们项目中肯定是固定的,所以我们无需担心格式泛滥,json的解析你可以任意写,不过还是推荐使用fastjson来搞,这样太方便了。
来看看根据这种格式写出来的parser什么样吧。
public class CommParser<T> implements Net.Parser<T> {
private String mKey;
public CommParser(String key) {
mKey = key;
}
@Override
public Result<T> parse(String response) {
Result<T> result = new Result<T>();
try {
JSONObject baseObject = JSON.parseObject(response);
if(!baseObject.getBooleanValue("success")) {
result.setMsg(baseObject.getString("message"));
}else {
Class<T> klass = Helper.generateType(getClass());
if(klass == null) throw new Exception();
T t = baseObject.getObject(mKey, klass);
result.setStatus(Result.SUCCESS);
result.setResult(t);
return result;
}
} catch (Exception e) {
e.printStackTrace();
result.setMsg(Net.ERR_PARSE_MSG);
}
result.setStatus(Result.ERROR);
return result;
}
}
首先这个Parser要知道我们关心哪个部分内容,所以我们需要在构造里传递一个key,对应上面的json格式就是user啦,接下来我们重写parse方法,使用fastjson将我们需要的数据解析出来了,这里面我们使用了Helper.generateType方法,这个方法是AndNet提供的一个方法,目的就是获取泛型的类型,我们CommParser的是泛型的。在你的项目中,你完全可以copy一下这个parser,然后改成你的逻辑。
ok, 既然parser我们定义好了,那我们接下来就进入AndNet的使用吧。
使用AndNet做get请求
get请求很简单,不需要任何参数,我们直接使用
Net.get(final String url, final Parser<T> parser, final Callback<T> callback);
就可以了
Net.get("http://192.168.3.116/?name=loader&age=18&city=jinan",
new CommParser<User>("user") {}, new Net.Callback<User>() {
@Override
public void callback(Result<User> result) {
if(result.getStatus() == Result.SUCCESS) {
User user = result.getResult();
mTextView.setText(user.getName());
mTextView.append("\n" + user.getAge());
mTextView.append("\n" + user.getCity());
}else {
mTextView.setText(result.getMsg());
}
}
});
调用一个方法,我们就搞定了从请求到解析的操作,是不是很方便!
使用AndNet做post请求
post请求估计是使用Net.post了,它的原型是:
Net.post(final String url, final RequestParams params, final Parser<T> parser, final Callback<T> callback);
仅仅多了一个RequestParams的参数,这个参数就是我们需要post的参数了,下面来看看post怎么使用,
RequestParams params = new RequestParams("name", "loader");
params.add("age", 18).add("city", "jinan");
Net.post("http://192.168.3.116/", params, new CommParser<User>("user") {
},
new Net.Callback<User>() {
@Override
public void callback(Result<User> result) {
if(result.getStatus() == Result.SUCCESS) {
User user = result.getResult();
mTextView.setText(user.getName());
mTextView.append("\n" + user.getAge());
mTextView.append("\n" + user.getCity());
}else {
mTextView.setText(result.getMsg());
}
}
});
和get一样简单,只不过是RequestParams构造出来的参数。另外AndNet还提供了另外一种post的方式,使用起来也特别爽-直接传递一个java bean!
首先我们定义一个参数的javabean,我们提交的参数有:name、age、city。
public class User implements IBaseBean {
@Annotation(key = "name")
private String name;
@Annotation(key = "age")
private int age;
@Annotation(key = "city")
private String city;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "name=" + name + ",age=" + age + ",city=" + city;
}
}
User实现了IBaseBean接口,这个接口是一个空接口,仅仅代表它是一个可以作为参数的类,User里的字段我们使用了Annotation
注解来标记它所对应的参数的key。
定义完bean后,我们接下来就是提交它的操作了。
User user = new User();
user.setName("qibin");
user.setCity("shandong");
user.setAge(18);
Net.post("http://192.168.3.116/", user, new CommParser<User>("user") {
}, new Net.Callback<User>() {
@Override
public void callback(Result<User> result) {
if(result.getStatus() == Result.SUCCESS) {
mTextView.setText(result.getResult().toString());
}else {
mTextView.setText(result.getMsg());
}
}
});
和上面普通的post一样,这里我们仅仅是将RequestParams替换成了User的对象。这种方式是不是看起来更加清爽呢!
文件上传
AndNet支持文件上传,不过这里的支持还是得依靠我们的HttpStack的实现,默认提供了OkHttpStack就支持文件上传操作,文件上传操作和我们上面说的post操作没有任何区别,只需要给RequestParams一个File类型的值就ok。
RequestParams params = new RequestParams("name", "qibin");
params.add("file", new File(Environment.getExternalStorageDirectory()
+ "/demo.doc"));
Net.post("http://192.168.3.116/upload.php", params, new Net.NoParser(),
new Net.Callback<String>() {
@Override
public void callback(Result<String> result) {
mTextView.setText(result.getResult() + "");
}
});
其他任何特殊的代码都没有,这样我们就完成了上传功能。
AndNet的高级使用-自定义HttpStack
上面提到过,AndNet支持切换使用的网络框架,这就需要我们自定义HttpStack来实现,自定义HttpStack我们需要继承AbsHttpStack
,下面我们就以自定义VolleyStack为例,替换默认的OkHttp,
public class VolleyStack<T> extends AbsHttpStack<T> {
private Application mContext;
public VolleyStack(Application context) {
mContext = context;
}
/**
* get请求
*
* @param url 网址
* @param parser 解析器
* @param callback 回调
*/
@Override
public void get(String url, WeakReference<Net.Parser<T>> parser,
WeakReference<Net.Callback<T>> callback) {
invoke(Request.Method.GET, url, null, parser, callback);
}
/**
* post请求
*
* @param url 访问的url
* @param params post参数
* @param parser 解析器
* @param callback 回调
*/
@Override
public void post(String url, RequestParams params,
WeakReference<Net.Parser<T>> parser,
WeakReference<Net.Callback<T>> callback) {
invoke(Request.Method.POST, url, params, parser, callback);
}
/**
* 执行网络请求
*
* @param url
* @param params post时请求的参数 get时为null
* @param parser
* @param callback
* @param method
*/
private void invoke(final int method, final String url,
final RequestParams params,
final WeakReference<Net.Parser<T>> parser,
final WeakReference<Net.Callback<T>> callback) {
StringRequest request = new StringRequest(method, url,
new Response.Listener<String>() {
public void onResponse(String response) {
onNetResponse(parser, callback, response);
}
}, new Response.ErrorListener() {
public void onErrorResponse(VolleyError error) {
error.printStackTrace();
onError(callback, Net.DEF_ERR_MSG);
}
}) {
@Override
protected Map<String, String> getParams()
throws AuthFailureError {
if (params != null) return params.get();
return super.getParams();
}
};
VolleyManager.getInstance(mContext).add(request);
}
@Override
public void cancel(String tag) {
VolleyManager.getInstance(mContext).cancel(tag);
}
}
这里重写了AbsHttpStack的get
和post
方法,这里面都调用了我们自定义的invoke
方法,在invoke
中我们使用Volley进行网络请求,在请求成功后调用了onNetResponse(final WeakReference<Net.Parser<T>> parser,final WeakReference<Net.Callback<T>> callback, final String response);
方法,
在请求失败后调用了onError(final WeakReference<Net.Callback<T>> callback, final String msg);
方法,这两个方法在AbsHttpStack
已经实现,我们无需关心。
好了,新的HttpStack定义好了,那我们就来切换一下吧。
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
Net.init(new VolleyStack(this));
// Net.init(new OkHttpStack());
}
}
修改一行代码,就完成了网络框架的切换,而我们的业务代码无需任何变动,是不是很爽?
AndNet的高级使用-添加header
有时候我们的项目需要一些自定义的header,我们完全可以通过扩展OkHttpStack
来完成这个功能。
public class OkHttpHeaderStack<T> extends OkHttpStack<T> {
@Override
public LinkedHashMap<String, String> headers() {
LinkedHashMap<String, String> headers = new LinkedHashMap<>();
headers.put("name", "header");
return headers;
}
}
我们继承了OkHttpStack
类,并重写了headers
方法,将我们需要的header放到一个map里返回,再次替换我们使用的HttpStack
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
// Net.init(new VolleyStack(this));
// Net.init(new OkHttpStack());
Net.init(new OkHttpHeaderStack());
}
}
完美解决! 好了,这样AndNet的功能我们就学习完了,最后是AndNet的下载地址,包含了源码、jar包和实例代码,欢迎各方star。
https://github.com/qibin0506/AndNet