Volley使用技巧-----更好的封装(cookie的使用)

Volley使用技巧—–更好的封装(cookie的使用)

题外话

上一篇讲到如何自定义Request以便更方便的使用Volley,这篇即将分享的是如何更好用进行封装,使volley使用起来更加的方便,简单,顺便带上了关于cookie的处理方法.

正题

回顾上一篇博客中提到使用volley最初步骤,即创建一个请求队列:

mQueue = new Volley.RequestQueue(getApplicationContext());

这样的话每到一个activity或者fragment中,就不得不去重新创建一个队列,每个队列的生命周期也跟随着activity或者fragment,为了避免这种繁琐的情况,可以自定义一个工具类,其中持有一个队列,这个队列的生命周期跟随整个应用.

搜寻了一下,发现android应用在创建的时候会有一个application类实例跟随着产生,如果对Application类不是很熟悉的话,可以参考这篇博客.下面是自定义出来的application类:

public class RequestQueueController extends Application{

  //关于cookie的关键字
  private static final String SET_COOKIE_KEY = "Set-Cookie";
  private static final String COOKIE_KEY = "Cookie";
  private static final String COOKIE_USERNAME = "username";

  //请求队列
  private RequestQueue _requestQuene;

  //SharedPreferences,用于存储少量的数据
  private SharedPreferences _preferences;

  //本类的实例
  private static RequestQueueController _instance;

  public static RequestQueueController get() {
    return _instance;
  }
  /**
   * 该方法在应用运行的时候就会自动调用
   */
  @Override
  public void onCreate() {
    super.onCreate();
    _instance = this;
    _preferences = getSharedPreferences(AppConstant.PREFERENCE_NAME,0);
    _requestQuene = Volley.newRequestQueue(this);
  }
  /**
   * 返回请求队列
   * @return
   */
  public RequestQueue getRequestQueue() {
    return _requestQuene;
  }
  /**
   * 用于检测返回头中包含的cookie
   * 并且更新本地存储的cookie
   * @param headers
   */
  public final void checkSessionCookie(Map<String, String> headers) {
    if (headers.containsKey(SET_COOKIE_KEY)) {
      String cookie = headers.get(SET_COOKIE_KEY);
      if((cookie.length()) > 0 && (!cookie.contains("saeut"))) {
        String[] splitCookie = cookie.split(";");
        String[] splitSessionId = splitCookie[0].split("=");
        cookie = splitSessionId[1];
        SharedPreferences.Editor prefEditor = _preferences.edit();
        prefEditor.putString(COOKIE_USERNAME, cookie);
        prefEditor.apply();
      }
    }
  }
  /**
   * 向请求头中加入cookie
   * @param headers
   */
  public final void addSessionCookie(Map<String, String> headers) {
    String sessionId = _preferences.getString(COOKIE_USERNAME, "");
    if (sessionId.length() > 0) {
      StringBuilder builder = new StringBuilder();
      builder.append(COOKIE_USERNAME);
      builder.append("=");
      builder.append(sessionId);
      if (headers.containsKey(COOKIE_KEY)) {
        builder.append("; ");
        builder.append(headers.get(COOKIE_KEY));
      }
      headers.put(COOKIE_KEY, builder.toString());
    }
  }
}

上面的自定义类继承了Application类,记住还需要在AndroidManifest.xml中的Application标签中加入RequestQueueController(自定义类名),将这个自定义类和Application绑定到一起,就可以在应用启动的时候执行onCreate()方法中的代码了;

处理好了请求队列的创建之后,再来分析request,之前使用request都是直接创建两个listener来处理,写在一起会让代码看上去冗余,就类似这样:

request.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {
        //处理请求成功返回的结果
        Response.Listener<String> listener = new Response.Listener<String>() {
          @Override
          public void onResponse(String s) {
            Log.e("dada", s);
          }
        };
        //处理请求错误返回的结果
        Response.ErrorListener errorListener = new Response.ErrorListener() {
          @Override
          public void onErrorResponse(VolleyError volleyError) {
            Log.e("error", volleyError.toString());
          }
        };
        //实例化请求对象
        StringRequest stringRequest = new StringRequest("http://www.baidu.com", listener, errorListener);
        //向队列中加入请求
        requestQueue.add(stringRequest);
        requestQueue.start();
      }
    });

可以模仿Angularjs那种模式来将这些分层,大致分为三层:

  1. 最底层的API,负责创建Request并加入请求队列,根据返回值的需求不同来封装.供第二层来调用.
  2. 将最顶层传入的信息传给最底层的API,并将请求返回的信息处理(根据自己的情况来处理),通过回调接口传递给顶层的调用者.
  3. 顶层的调用者只需要给出相应的第二层调用和相关参数,其余可以不用管理.

经过上面三层的分离之后,每一层都有明确的分工,而且互不干扰,更方便开发者调用,下面给出上面三层的代码(封装了JSONArrayRequestPlus的API,其余的是相同的道理):

/**
 * 最底层的API
 * 只根据传来的参数创建了Request
 * 并将其加入了队列中
 */
public class HttpApi {
  /**
   * 返回JsonArray的网络请求Api
   * @param method
   * @param url
   * @param requestBody
   * @param listener
   * @param errorListener
   */

  public static void DoJsonArrayRequest(int method,
                                        String url,
                                        HashMap hashMap,
                                        Response.Listener<JSONArray> listener,
                                        Response.ErrorListener errorListener) {
    final HashMap<String,String> map = hashMap;

    try{
      JsonArrayRequestPlus jsonArrayRequestPlus = new JsonArrayRequestPlus(method, url, listener, errorListener){
        @Override
        protected Map<String, String> getParams() throws AuthFailureError {
          return map;
        }
      };     RequestQueueController.get().getRequestQueue().add(jsonArrayRequestPlus);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

最底层的API弄好之后,第二层就对其直接调用,也就是第三层调第二层,第二层调第一层,返回结果给第二层做处理,再回传需要的结果给顶层的调用者.

/**
 * 第二层相当与传输层
 * 也负责了对数据进行处理
 */
public class HttpService {
  /**
   * 登录请求
   */

//自持有一个接口,这个接口就是用来传递结果的,接口的定义就在下面一行,两个函数分别对应着Volley给出的两个接口
  private static OnLoginRequestResponseListener mLoginRequestListener;
  public static interface OnLoginRequestResponseListener {
    public void OnLoginSuccessResponse(JSONArray jsonArray);
    public void OnLoginErrorResponse(String errorResult);
  }
  public static void DoLoginRequest (int method,
                                     String url,
                                     HashMap<String,String> hashMap,
                                     OnLoginRequestResponseListener listener
  ) {
    mLoginRequestListener = listener;
    Response.Listener<JSONArray> responseListener = new Response.Listener<JSONArray>() {
      @Override
      public void onResponse(JSONArray jsonArray) {
        mLoginRequestListener.OnLoginSuccessResponse(jsonArray);
      }
    };

    Response.ErrorListener errorListener = new Response.ErrorListener() {
      @Override
      public void onErrorResponse(VolleyError volleyError) {
        mLoginRequestListener.OnLoginErrorResponse(volleyError.getMessage());
      }
    };
    HttpApi.DoJsonArrayRequest(method, url, hashMap, responseListener, errorListener);
  }

  /**
   * 注册请求
   */
//这个类似于上面的,调用的是同一个底层的接口,一次封装多次调用,很方便
  private static OnSignupRequestResponseListener mSignupRequestListener;
  public static interface OnSignupRequestResponseListener {
    public void OnSignupSuccessResponse(JSONArray jsonArray);
    public void OnSignupErrorResponse(String errorResult);
  }
  public static void DoSignupRequest (int method,
                                      String url,
                                      HashMap<String, String> hashMap,
                                      OnSignupRequestResponseListener listener
  ) {
    mSignupRequestListener = listener;
    Response.Listener<JSONArray> responseListener = new Response.Listener<JSONArray>() {
      @Override
      public void onResponse(JSONArray jsonArray) {
        mSignupRequestListener.OnSignupSuccessResponse(jsonArray);
      }
    };

    Response.ErrorListener errorListener = new Response.ErrorListener() {
      @Override
      public void onErrorResponse(VolleyError volleyError) {
        mSignupRequestListener.OnSignupErrorResponse(volleyError.getMessage());
      }
    };
    HttpApi.DoJsonArrayRequest(method, url, hashMap, responseListener, errorListener);
  }
}

第二层弄完了之后,第三层就剩下实现回调接口以及调用了,实现的代码如下:

public class MainActivity extends ActionBarActivity 
        implements HttpService.OnLoginRequestResponseListener{

  //提交请求的按钮
  private Button request;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    request.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View view) {

        HttpService.DoLoginRequest(Request.Method.POST,url,map,MainActivity.this);
      }
    });
  }

//后面这两个重写的方法就是第二层中需要调用的回调方法,在这里接收到信息后做出响应,这里没有给出具体的处理代码
  @Override
  public void OnLoginSuccessResponse(JSONArray jsonArray) {

  }

  @Override
  public void OnLoginErrorResponse(String errorResult) {

  }
}
关于cookie

在开头的自定义Application类中已经定义了两个方法,就是存取cookie值的方法,只需要在自定义的request中加入这两个方法就可以了,相关加入位置如下:

public class JsonArrayRequestPlus extends Request<JSONArray>{

  private final Response.Listener<JSONArray> mListener;

  public JsonArrayRequestPlus(int method,
                              String url,
                              Response.Listener<JSONArray> listener,
                              Response.ErrorListener errorListener) {
    super(method, url, errorListener);
    mListener = listener;
  }

//重写getHeader()方法,请求会自动调用这个方法来获取请求头部,所以我们将本地的cookie存放进一个map返回回去,cookie就会包含到header里面去
  @Override
  public Map<String, String> getHeaders() throws AuthFailureError {
    Map<String, String> headers = super.getHeaders();

    if(headers == null || headers.equals(Collections.emptyMap())) {

      headers = new HashMap<>();
    }
//这个方法就是自定义Application类中添加cookie的方法
RequestQueueController.get().addSessionCookie(headers);
    return headers;
  }

  @Override
  protected void deliverResponse(JSONArray jsonArray) {
    mListener.onResponse(jsonArray);
  }

  @Override
  protected Response<JSONArray> parseNetworkResponse(NetworkResponse response) {

//在处理返回信息的时候,服务器会返回cookie,在这里截取到cookie并且存储到本地
RequestQueueController.get().checkSessionCookie(response.headers);

    try {
      String jsonString =
              new String(response.data, HttpHeaderParser.parseCharset(response.headers));
      return Response.success(new JSONArray(jsonString),
              HttpHeaderParser.parseCacheHeaders(response));
    } catch (UnsupportedEncodingException e) {
      return Response.error(new ParseError(e));
    } catch (JSONException je) {
      return Response.error(new ParseError(je));
    }
  }
}

关于这些如果还有什么不明白的,可以直接给小达留言,或者直接加QQ2319821734,希望能和大家相互学习交流,共同进步~今天就到这里咯,晚安~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值