2016年,关于retrofit和okhttp这两个话题非常火,retrofit+okhhtp已经成为Android网络请求的主流框架了,看了一下现在公司的项目,还是使用的原始的HttpURLConnection,瞬间感觉有点low,通过自己的学习,决定对公司的网络请求进行一下改造,在这里做一下简单的总结,希望大家多多指正。
retrofit是一个基于okhttp的,适用于Android,Java的网络请求工具。我觉得它其实就是对okhttp做一下统一的封装,方便广大开发者的更快捷、更方便的使用。如果你对retrofit还不是很熟悉,可以去Retrofit官网了解下,我也会在接下来做个简单的使用说明。它既然这么火,而且已经进行很好的封装了,但是我们为什么还要对它封装呢?因为每个公司的业务不一样,这个框架大而且全,其实很多在我们的业务里面根本使用不到,所以我们需要个性化定制。
首先创建一个网络请求API的Interface
public interface GitHubService {
@GET("users/{user}/repos")
Call> listRepos(@Path("user") String user);
}
初始化Retrofit,并创建一个GitHubService interface
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.build();
GitHubService service = retrofit.create(GitHubService.class);
对GitHubService的方法进行同步或者一部的访问,来实现网络的请求(使用enqueue 或者 execute来执行发起请求,enqueue是是异步执行,而 execute是同步执行)
Call> repos = service.listRepos("octocat");
上面就是官网对retrofit的简单讲解,下面就进行我们的简单封装。
因为公司的网络请求都是在common包里面处理的,而和这个包是不会经常改动的,但是每次增加一个求情,都要改动一下common包里面的网络请求的Interface,这个不利于模块的解耦。下面是我对Interface的改造:
public interface NetInterface {
@GET
Call get(@Url String url);
@POST
Call post(@Url String url, @Body RequestBody body);
@Multipart
@POST
Call updateFile(@Url String url, @Part MultipartBody.Part file, @PartMap HashMap map);
}
定义了三个方法,get、post、updateFile对应网络请求的GET、POST和文件上传,这样每次就只需传入一个url就可以进行网络请求,不用每次都去更改。
public class NetUtils {
private static NetUtils INSTANCE;
private OkHttpClient mClient;
private Retrofit mRetrofit;
private ArrayList callLists=new ArrayList<>();
private NetUtils() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(15, TimeUnit.SECONDS);
builder.addInterceptor(new NetInterceptor());
mClient = builder.build();
mRetrofit = new Retrofit.Builder()
.baseUrl("")
.addConverterFactory(FastjsonConverterFactory.create())
.client(mClient)
.build();
}
public static NetUtils getInstance() {
if (INSTANCE == null) {
synchronized (NetUtils.class) {
if (INSTANCE == null) {
INSTANCE = new NetUtils();
}
}
}
return INSTANCE;
}
public Call get(String url) {
return mRetrofit.create(NetInterface.class).get(url);
}
public Call post(String url, FormBody body) {
return mRetrofit.create(NetInterface.class).post(url, body);
}
public Call updateFile(String url, MultipartBody.Part file, HashMap body) {
return mRetrofit.create(NetInterface.class).updateFile(url, file, body);
}
}
在这里,可以设置缓存,设置统一的网络拦截器……,我这边写的都比较简单
public class NetInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Response respone = chain.proceed(chain.request());
Log.d("TAG", respone.request().url() + "");
Log.d("TAG", respone.body() + "");
return respone;
}
}
public class NetLoader {
private ArrayList callList = new ArrayList<>();
private HashMap callMap = new HashMap<>();
private String TAG = "TAG";
public Call get(String url, Callback callback) {
Call call = NetUtils.getInstance().get(url);
call.enqueue(callback);
callList.add(call);
return call;
}
public Call get(String url, String tag, Callback callback) {
Call call = NetUtils.getInstance().get(url);
callList.add(call);
return call;
}
public Call post(String url, String postStr, Callback callback) {
FormBody.Builder builder = new FormBody.Builder();
String[] maps = postStr.split("&");
for (String s : maps) {
String key = s.substring(0, s.indexOf("="));
String value = s.substring(s.indexOf("=") + 1, s.length());
builder.add(key, value);
}
Call call = NetUtils.getInstance().post(url, builder.build());
call.enqueue(callback);
callList.add(call);
return call;
}
public Call updateFile(String url, String postStr, String fileKey, File file, Callback callback) {
HashMap map = new HashMap<>();
String[] maps = postStr.split("&");
for (String s : maps) {
String key = s.substring(0, s.indexOf("="));
String value = s.substring(s.indexOf("=") + 1, s.length());
RequestBody body = RequestBody.create(MediaType.parse("text/plain"), value);
map.put(key, body);
}
RequestBody requestFile =
RequestBody.create(MediaType.parse("multipart/form-data"), file);
MultipartBody.Part body =
MultipartBody.Part.createFormData(fileKey, file.getName(), requestFile);
Call call = NetUtils.getInstance().updateFile(url, body, map);
call.enqueue(callback);
callList.add(call);
return call;
}
public void destroy() {
for (Call call : callList) {
call.cancel();
}
}
public void removeCall(Call call) {
callList.remove(call);
}
}
其实上面的NetUtils已经满足了我们的网络请求,为什么还要把它包装到NetLoader里面呢?原因是为了我们
我们可以通过在每个Activity或者Fragment里面新建一个netLoader示例,在destroy方法里面调用netloader. destroy()方法,就可以实现与之周期进行绑定,防止异常。
我们还可以对请求返回的callback就行同意的处理:
public class NetCallBack implements Callback {
private WeakReference reference;
public NetCallBack(Context context){
reference=new WeakReference(context);
}
@Override
public void onResponse(Call call, Response response) {
if(response.body()==null){
Toast.makeText(reference.get(), "返回为空", Toast.LENGTH_SHORT).show();
}else{
//TODO 其他的一些判断,如登陆或者其他的统一操作
}
}
@Override
public void onFailure(Call call, Throwable t) {
Toast.makeText(reference.get(), "网络连接错误", Toast.LENGTH_SHORT).show();
}
}
当网络请求失败的时候,我们可以统一的弹窗处理,当用户没登录时,我们可以自己跳到登录页……
以上就是我对网络请求的简单封装,欢迎大家向我吐槽!