Android网络请求的封装方法

项目的代码中看到了这样一种的方法(就称之为“Gson泛型”吧)来封装网络请求,简单、方便、条理清晰,自己用后感觉非常nice,特此记录下来。
首先是网络请求需要注意的几个点:
第一:如何使用规范简洁的代码来实现网络架构?
第二:数据解析要用什么方法?
第三:网络异常如何统一处理?

1.定义网络封装类

/**

  • 网络请求封装

  • Created by kuaigeng01 on 2018/1/20.
    */
    public class ServerRequest {
    public static final int Error_from_net = 1;
    public static final int Error_from_server = 2;
    public static final int Error_from_parser = 3;

    /**

    • 发起网络请求,回调在ui线程
    • @param tagPrefix 请求前缀:用于设置请求的Tag,这样能根据tag取消请求
    • @param tClass 需要返回的数据类型
    • @param url 请求url
    • @param params 请求参数
    • @param callback 回调
    • @param 数据类型
      */
      public static void sendRequestCallbackInMainThread(String tagPrefix, Class tClass,
      String url, Map params, RequestCallback callback) {
      sendRequest(tagPrefix, true, tClass, url, params, callback);
      }

/**

  • 发起网络请求,回调在非ui线程

  • @param tagPrefix 请求前缀:用于设置请求的Tag,这样能根据tag取消请求

  • @param tClass 需要返回的数据类型

  • @param url 请求url

  • @param params 请求参数

  • @param callback 回调

  • @param 数据类型
    */
    public static void sendRequestCallbackInBackgroundThread(String tagPrefix, Class tClass,
    String url, Map params, RequestCallback callback) {
    sendRequest(tagPrefix, false, tClass, url, params, callback);
    }
    public static void cancelRequest(String tagPrefix, String url) {
    if (TextUtils.isEmpty(url)) {
    return;
    }
    String tag = createTag(tagPrefix, url);
    RequestQueue queue = VolleyHelper.getInstance().getRequestQueue();
    queue.cancelAll(tag);
    queue = VolleyHelper.getInstance().getAsyncRequestQueue();
    queue.cancelAll(tag);
    }

    private static void sendRequest(String tagPrefix, boolean callbackInMainThread,
    final Class tClass, final String url, Map params,
    final RequestCallback callback) {
    sendRequestImpl(tagPrefix, callbackInMainThread, url, params,
    new Response.Listener() {
    @Override public void onResponse(String s) {
    ServerResult result = ServerDataParser.simpleParseJsonToPojo(tClass, s);
    if (null != result) {
    if (result.getStatus() == 200) {
    if (null != callback) {
    callback.onSuccess(result.getData());
    }
    } else {
    if (null != callback) {

                                 callback.onFailure(Error_from_server, TextUtils.isEmpty(result.getMsg())?"":result.getMsg());
                             }
                         }
                     } else {
                         if (null != callback) {
                             callback.onFailure(Error_from_parser, "parse json failure");
                         }
                     }
                 }
             }, new Response.ErrorListener() {
                 @Override public void onErrorResponse(VolleyError volleyError) {
                     if (null != callback) {
                         callback.onFailure(Error_from_net, String.valueOf(volleyError));
                     }
                 }
             });
    

    }

    private static void sendRequestImpl(String tagPrefix, boolean callbackInMainThread, String url,
    Map params, Response.Listener listener,
    Response.ErrorListener errorListener) {

     if (TextUtils.isEmpty(url)) {
         throw new IllegalArgumentException("url can't be empty!!!");
     }
    
     if (TextUtils.isEmpty(tagPrefix)) {
         throw new IllegalArgumentException("tagPrefix can't be empty!!!");
     }
    
     if (null == params) {
         params = getCommonRequestParams();
     } else {
         params.putAll(getCommonRequestParams());
     }
    
     AcosStringRequest request = new AcosStringRequest(url, params, listener, errorListener);
    
     RequestQueue queue;
     if (callbackInMainThread) {
         queue = VolleyHelper.getInstance().getRequestQueue();
    

// queue = PluginAnswerLiveCooperation.getInstance().getRequestQueue();
} else {
// queue = PluginAnswerLiveCooperation.getInstance().getAsyncRequestQueue();
queue = VolleyHelper.getInstance().getAsyncRequestQueue();
}

    String tag = createTag(tagPrefix, url);
    request.setTag(tag);

    queue.cancelAll(tag);
    queue.add(request);
}

public interface RequestCallback {
    void onSuccess(T data);

    void onFailure(int from, String errorMsg);
}

private static String createTag(String tagPrefix, String url) {
    return tagPrefix + "_" + StringUtils.calcMd5(url);//用于 同一个url请求,cancel掉掉旧掉
}

private static HashMap getCommonRequestParams() {
    HashMap map = new HashMap<>();

    User user = AnswerDataCenter.getInstance().getHostUser();
    String token = user == null ? "" : user.token;

    map.put("token", token);
    map.put("_appid", "10000");
    return map;
}

}

这个类做了这么几件事:
1)定义三种请求异常的类型,分别是网络异常、服务器异常、解析异常。
2)定义一个发起网络请求的方法,回调在UI线程(同时定义了一个回调在非UI线程的方法),各个参数的含义在代码中已经注释的很明白。重要的一点需要注意的是泛型的参数。
3)定义一个取消网络请求的方法,在发起请求的时候传入了一个tag设置到请求对象中,取消的时候也会用到那个tag。
4)例子中使用的是Volley网络请求库,在sendRequestImpl中设置Volley的请求参数。
5)定义RequestCallback接口,Volley回调使用,传入的参数为用户定义的实体类对象,定义为泛型的原因是为了实现Gson统一解析数据。
sendRequest方法中调用sendRequestImpl方法请求数据,在onResponse方法回调中处理返回的数据,这个时候就会调用服务端数据解析器ServerDataParser.simpleParseJsonToPojo(tClass,s),第一个参数是json字符串解析成的最终类。接下来看数据解析器里面是如何处理服务器返回的json字符串。
2.服务端数据解析器

public class ServerDataParser {

private static final TypeAdapter booleanAsIntAdapter = new TypeAdapter() {
    @Override
    public void write(JsonWriter out, Boolean value) throws IOException {
        if (value == null) {
            out.nullValue();
        } else {
            out.value(value);
        }
    }

    @Override
    public Boolean read(JsonReader in) throws IOException {
        JsonToken peek = in.peek();
        switch (peek) {
            case BOOLEAN:
                return in.nextBoolean();
            case NULL:
                in.nextNull();
                return null;
            case NUMBER:
                return in.nextInt() != 0;
            case STRING:

                String val = in.nextString();
                if (TextUtils.equals("1", val)) {
                    return true;
                }

                if (TextUtils.equals("0", val)) {
                    return false;
                }

                return Boolean.parseBoolean(val);
            default:
                throw new IllegalStateException("Expected BOOLEAN or NUMBER but was " + peek);
        }
    }
};

public static Gson createGson() {
    Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd hh:mm:ss").excludeFieldsWithoutExposeAnnotation().
            registerTypeAdapter(Boolean.class, booleanAsIntAdapter).
            registerTypeAdapter(boolean.class, booleanAsIntAdapter).create();

    return gson;
}

public static  ServerResult simpleParseJsonToPojo(Class tClass, String json) {
    if (TextUtils.isEmpty(json)) {
        return null;
    }

    Type type = new ParameterizedTypeImpl(ServerResult.class, new Class[]{tClass});

    try {

        Gson gson = createGson();
        ServerResult parseResult = gson.fromJson(json, type);

        return parseResult;

    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

}
数据解析器设置了Gson的一些参数,然后就调用Gson的泛型,得到传入实体类的Type对象,用来供gson.fromJson()使用。

3.Gson泛型
定义gson泛型类

public class ParameterizedTypeImpl implements ParameterizedType {
private final Class raw;
private final Type[] args;

public ParameterizedTypeImpl(Class raw, Type[] args) {
    this.raw = raw;
    this.args = args != null ? args : new Type[0];
}

@Override
public Type[] getActualTypeArguments() {
    return args;
}

@Override
public Type getRawType() {
    return raw;
}

@Override
public Type getOwnerType() {
    return null;
}

}
Gson泛型的作用,就是将传进来的实体类转换成gson能够识别的Type类型。
4.数据实体类
移动端请求接口得到的数据,大致都是统一格式的,例如下面这种:

public class ServerResult {
@SerializedName("status")
@Expose
private int status;

@SerializedName("msg")
@Expose
private String msg;

@SerializedName("result")
@Expose
private T data;

public T getData() {
    return data;
}

public void setData(T data) {
    this.data = data;
}

public int getStatus() {
    return status;
}

public void setStatus(int status) {
    this.status = status;
}

public String getMsg() {
    return msg;
}

public void setMsg(String msg) {
    this.msg = msg;
}

}

这里是一个实体类的基类,之后所有的实体类都会继承它。
一个状态码字段status,一个错误信息字段msg,一个result对象。
这里的result对象定义为泛型,是为了编译之后的统一解析。
总结一下封装步骤:
1.创建ServerRequest网络请求类,调用sendRequest方法请求网络,tClass泛型类,继承自ServerResult。
2.网络请求成功,返回json字符串s,然后调用服务器端解析器ServerDataParser.simpleParseJsonToPojo(tClass,s);网络请求失败,则调用callback.onFailure(),传入失败类型和失败原因。
3.在simpleParseJsonToPojo方法中,调用
Type type=ParameterizedTypeImpl(ServerResult.class,new Class[]{tClass});
返回泛型的Type类型,然后调用
ServerResult result=gson.fromJson(json,type);
最后得到Gson解析的实体对象。

你可能感兴趣的:(Android网络请求的封装方法)