美文网首页
Android网络请求的封装方法

Android网络请求的封装方法

作者: 明明_白_白 | 来源:发表于2018-09-14 11:44 被阅读696次

    项目的代码中看到了这样一种的方法(就称之为“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 <T> 数据类型
        */
        public static <T> void sendRequestCallbackInMainThread(String tagPrefix, Class<T> tClass,
        String url, Map<String, String> params, RequestCallback<T> callback) {
        sendRequest(tagPrefix, true, tClass, url, params, callback);
        }

    /**

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

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

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

    • @param url 请求url

    • @param params 请求参数

    • @param callback 回调

    • @param <T> 数据类型
      */
      public static <T> void sendRequestCallbackInBackgroundThread(String tagPrefix, Class<T> tClass,
      String url, Map<String, String> params, RequestCallback<T> 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 <T> void sendRequest(String tagPrefix, boolean callbackInMainThread,
      final Class<T> tClass, final String url, Map<String, String> params,
      final RequestCallback<T> callback) {
      sendRequestImpl(tagPrefix, callbackInMainThread, url, params,
      new Response.Listener<String>() {
      @Override public void onResponse(String s) {
      ServerResult<T> 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<String, String> params, Response.Listener<String> 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<T extends Object> {
        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<String, String> getCommonRequestParams() {
        HashMap<String, String> 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<Boolean> booleanAsIntAdapter = new TypeAdapter<Boolean>() {
        @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 <T> ServerResult<T> simpleParseJsonToPojo(Class<T> tClass, String json) {
        if (TextUtils.isEmpty(json)) {
            return null;
        }
    
        Type type = new ParameterizedTypeImpl(ServerResult.class, new Class[]{tClass});
    
        try {
    
            Gson gson = createGson();
            ServerResult<T> 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<T> {
    @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<T> result=gson.fromJson(json,type);
    最后得到Gson解析的实体对象。

    相关文章

      网友评论

          本文标题:Android网络请求的封装方法

          本文链接:https://www.haomeiwen.com/subject/xcqogftx.html