前言
2016年,关于retrofit和okhttp这两个话题非常火,retrofit+okhhtp已经成为Android网络请求的主流框架了,看了一下现在公司的项目,还是使用的原始的HttpURLConnection,瞬间感觉有点low,通过自己的学习,决定对公司的网络请求进行一下改造,在这里做一下简单的总结,希望大家多多指正。
Retrofit
retrofit是一个基于okhttp的,适用于Android,Java的网络请求工具。我觉得它其实就是对okhttp做一下统一的封装,方便广大开发者的更快捷、更方便的使用。如果你对retrofit还不是很熟悉,可以去Retrofit官网了解下,我也会在接下来做个简单的使用说明。它既然这么火,而且已经进行很好的封装了,但是我们为什么还要对它封装呢?因为每个公司的业务不一样,这个框架大而且全,其实很多在我们的业务里面根本使用不到,所以我们需要个性化定制。
首先创建一个网络请求API的Interface
1 2 3 4
| public interface GitHubService { @GET("users/{user}/repos") Call<List<Repo>> listRepos(@Path("user") String user); }
|
初始化Retrofit,并创建一个GitHubService interface
1 2 3 4 5 6 7 8 9
| Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com/") .build();
GitHubService service = retrofit.create(GitHubService.class); ``` 3. 对GitHubService的方法进行同步或者一部的访问,来实现网络的请求(使用enqueue 或者 execute来执行发起请求,enqueue是是异步执行,而 execute是同步执行)
|
Call> repos = service.listRepos(“octocat”);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 上面就是官网对retrofit的简单讲解,下面就进行我们的简单封装。 # Interface的改造 因为公司的网络请求都是在common包里面处理的,而和这个包是不会经常改动的,但是每次增加一个求情,都要改动一下common包里面的网络请求的Interface,这个不利于模块的解耦。下面是我对Interface的改造:
```java 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<String, RequestBody> map); }
|

定义了三个方法,get、post、updateFile对应网络请求的GET、POST和文件上传,这样每次就只需传入一个url就可以进行网络请求,不用每次都去更改。
Retrofit的封装NetUtils
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| public class NetUtils { private static NetUtils INSTANCE; private OkHttpClient mClient; private Retrofit mRetrofit; private ArrayList<Call> 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<String, RequestBody> body) { return mRetrofit.create(NetInterface.class).updateFile(url, file, body); }
}
|
在这里,可以设置缓存,设置统一的网络拦截器……,我这边写的都比较简单
1 2 3 4 5 6 7 8 9 10
| 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; } }
|
简单的打印url,也可以在这里添加一些通用的参数

请求工具类NetLoader
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| public class NetLoader { private ArrayList<Call> callList = new ArrayList<>(); private HashMap<String, Call> 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<String, RequestBody> 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的封装
我们还可以对请求返回的callback就行同意的处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class NetCallBack implements Callback { private WeakReference<Context> reference; public NetCallBack(Context context){ reference=new WeakReference<Context>(context); }
@Override public void onResponse(Call call, Response response) { if(response.body()==null){ Toast.makeText(reference.get(), "返回为空", Toast.LENGTH_SHORT).show(); }else{
} }
@Override public void onFailure(Call call, Throwable t) { Toast.makeText(reference.get(), "网络连接错误", Toast.LENGTH_SHORT).show(); }
}
|
当网络请求失败的时候,我们可以统一的弹窗处理,当用户没登录时,我们可以自己跳到登录页……
以上就是我对网络请求的简单封装,欢迎大家向我吐槽!
感谢鼓励