前言

2016年,关于retrofit和okhttp这两个话题非常火,retrofit+okhhtp已经成为Android网络请求的主流框架了,看了一下现在公司的项目,还是使用的原始的HttpURLConnection,瞬间感觉有点low,通过自己的学习,决定对公司的网络请求进行一下改造,在这里做一下简单的总结,希望大家多多指正。

Retrofit

retrofit是一个基于okhttp的,适用于Android,Java的网络请求工具。我觉得它其实就是对okhttp做一下统一的封装,方便广大开发者的更快捷、更方便的使用。如果你对retrofit还不是很熟悉,可以去Retrofit官网了解下,我也会在接下来做个简单的使用说明。它既然这么火,而且已经进行很好的封装了,但是我们为什么还要对它封装呢?因为每个公司的业务不一样,这个框架大而且全,其实很多在我们的业务里面根本使用不到,所以我们需要个性化定制。

  1. 首先创建一个网络请求API的Interface

    1
    2
    3
    4
    public interface GitHubService {
    @GET("users/{user}/repos")
    Call<List<Repo>> listRepos(@Path("user") String user);
    }
  2. 初始化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);
    }

Interface改造

定义了三个方法,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,也可以在这里添加一些通用的参数
NetInterceptor

请求工具类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{
//TODO 其他的一些判断,如登陆或者其他的统一操作

}
}

@Override
public void onFailure(Call call, Throwable t) {
Toast.makeText(reference.get(), "网络连接错误", Toast.LENGTH_SHORT).show();
}

}

当网络请求失败的时候,我们可以统一的弹窗处理,当用户没登录时,我们可以自己跳到登录页……

以上就是我对网络请求的简单封装,欢迎大家向我吐槽!