Android 網(wǎng)絡(luò)Volley學(xué)習(xí)

引言:對于網(wǎng)絡(luò)請求這塊來說最早接觸是AsyncHttpClient后來又簡單接觸了xUtils再后來就是OkHttp了,官方的Volley只是聽說過,并沒有真正使用過。

時(shí)間:2016年12月03日00:18:35

作者:JustDo23

GitHub:https://github.com/mcxiaoke/android-volley

01. 簡介

在慕課網(wǎng)上找了相關(guān)視頻Android-Volley詳解

Volley是 Google 在2013年推出的 Android 平臺(tái)的網(wǎng)絡(luò)通信庫。Volley特點(diǎn),快捷,簡單,網(wǎng)絡(luò)圖像,高效異步處理請求排序,緩存,多級(jí)別取消,和 Activity 生命周期聯(lián)動(dòng);缺點(diǎn)是不適合進(jìn)行文件的上傳下載。

Volley的請求同樣是包含有getpost請求;同時(shí)根據(jù)返回結(jié)果的不同可以挑選使用StringRequestJsonObjectRequestJsonArrayRequest;請求回調(diào)有SuccessError等回調(diào);全局建立一個(gè)請求隊(duì)列,方便網(wǎng)絡(luò)請求的添加取消;使用tag標(biāo)簽方便查找請求,并管理請求的取消,和 Activity 進(jìn)行聯(lián)動(dòng)使用。

建議:在這里強(qiáng)調(diào)一下,不論使用的是什么網(wǎng)絡(luò)請求框,都應(yīng)該自己進(jìn)行一下二次封裝,方便同一管理。

02. 入門代碼

Gradle文件中導(dǎo)入依賴

compile 'com.android.volley:volley:1.0.0'

新建Application并實(shí)例化請求隊(duì)列

public class JustApplication extends Application {

  private static RequestQueue requestQueue;// 全局的請求隊(duì)列

  @Override
  public void onCreate() {
    super.onCreate();
    requestQueue = Volley.newRequestQueue(this);// 實(shí)例化請求隊(duì)列
  }

  public static RequestQueue getRequestQueue() {
    return requestQueue;
  }
}

在 Activity 中進(jìn)行網(wǎng)絡(luò)請求

private void doStringGet() {
    String url = "https://www.baidu.com";// 參數(shù):[請求方式][請求鏈接][成功回調(diào)][失敗回調(diào)]
    StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {

      @Override
      public void onResponse(String response) {
        LogUtil.e(response);// 這個(gè)是成功的回調(diào)
      }
    }, new Response.ErrorListener() {

      @Override
      public void onErrorResponse(VolleyError error) {
        LogUtil.e(error.toString());// 這個(gè)是失敗的回調(diào)
      }
    });
    stringRequest.setTag("doVolleyGet");// 設(shè)置標(biāo)簽
    JustApplication.getRequestQueue().add(stringRequest);// 將請求添加進(jìn)隊(duì)列
}

使用POST方式進(jìn)行網(wǎng)絡(luò)請求,和GET方式不同的是需要將參數(shù)進(jìn)行封裝

private void doStringPost() {
    String url = "https://www.baidu.com";// 參數(shù):[請求方式][請求鏈接][成功回調(diào)][失敗回調(diào)]
    StringRequest stringRequest = new StringRequest(Request.Method.POST, url, null, null) {// 重寫父類的方法,返回網(wǎng)絡(luò)請求的參數(shù)

      @Override
      protected Map<String, String> getParams() throws AuthFailureError {
        Map<String, String> params = new HashMap<>();
        params.put("phone", "15812345678");
        params.put("key", "abcdefghigklmn");
        return params;
      }
    };
    stringRequest.setTag("doStringPost");// 設(shè)置標(biāo)簽
    JustApplication.getRequestQueue().add(stringRequest);// 將請求添加進(jìn)隊(duì)列
}

另外使用JsonObjectRequest進(jìn)行網(wǎng)絡(luò)請求和StringRequest也有些區(qū)別,就是不用重寫返回參數(shù),而是將一個(gè)JsonObject對象的參數(shù)直接進(jìn)行傳遞。

private void doJsonPost() {
    String url = "https://www.baidu.com";
    Map<String, String> params = new HashMap<>();
    params.put("phone", "15812345678");
    params.put("key", "abcdefghigklmn");
    JSONObject jsonObject = new JSONObject(params);// 將 Map 轉(zhuǎn)為 JsonObject 的參數(shù)
    // 參數(shù):[請求方式][請求鏈接][請求參數(shù)][成功回調(diào)][失敗回調(diào)]
    JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, url, jsonObject, new Response.Listener<JSONObject>() {

      @Override
      public void onResponse(JSONObject response) {
        LogUtil.e(response.toString());// 這個(gè)是成功的回調(diào)
      }
    }, null);
    jsonObjectRequest.setTag("doJsonPost");// 設(shè)置標(biāo)簽
    JustApplication.getRequestQueue().add(jsonObjectRequest);// 將請求添加進(jìn)隊(duì)列
}

在現(xiàn)有代碼的基礎(chǔ)上,給界面添加一個(gè) TextView 并在 Volley 網(wǎng)絡(luò)請求的回調(diào)中直接將返回的數(shù)據(jù)設(shè)置給 TextView ,測試發(fā)現(xiàn)回調(diào)可以直接操作UI。

03. 加載網(wǎng)絡(luò)圖片

方式一:直接請求圖片 URL 并將圖片進(jìn)行顯示

public void getNetImage() {
    String imageUrl = "http://img4.duitang.com/uploads/item/201509/30/20150930002351_3vHWx.thumb.700_0.jpeg";
    // 參數(shù):[圖片Url][成功回調(diào)][圖片最大寬度][圖片最大高度][填充方式][位圖配置][失敗回調(diào)]
    ImageRequest imageRequest = new ImageRequest(imageUrl, new Response.Listener<Bitmap>() {

      @Override
      public void onResponse(Bitmap response) {
        iv_show.setImageBitmap(response);// 請求成功返回 Bitmap 方便使用
      }// [圖片最大寬度][圖片最大高度]給0表示原圖顯示,否則會(huì)進(jìn)行壓縮
    }, 0, 0, ImageView.ScaleType.CENTER_CROP, Bitmap.Config.RGB_565, new Response.ErrorListener() {

      @Override
      public void onErrorResponse(VolleyError error) {
        iv_show.setImageResource(R.mipmap.ic_launcher);// 請求失敗的回調(diào)
      }
    });
    imageRequest.setTag("getNetImage");// 設(shè)置標(biāo)簽
    JustApplication.getRequestQueue().add(imageRequest);// 添加進(jìn)隊(duì)列
}

方式二:使用 ImageLoader 配合 ImageCache 及 ImageListener 進(jìn)行圖片顯示

public void getNetImage() {
    String imageUrl = "http://img4.duitang.com/uploads/item/201509/30/20150930002351_3vHWx.thumb.700_0.jpeg";
    // [獲取一個(gè) ImageLoader 對象] 參數(shù):[請求隊(duì)列][圖片緩存對象]
    ImageLoader imageLoader = new ImageLoader(JustApplication.getRequestQueue(), new BitmapCache());
    // [獲取一個(gè) ImageListener 對象] 參數(shù):[ ImageView ][默認(rèn)顯示圖片][加載失敗顯示圖片]
    ImageLoader.ImageListener imageListener = ImageLoader.getImageListener(iv_show, R.mipmap.ic_launcher, R.mipmap.ic_launcher);
    // [使用 ImageLoader 加載圖片] 參數(shù):[圖片Url][圖片加載監(jiān)聽][圖片最大寬度][圖片最大高度][填充方式]
    imageLoader.get(imageUrl, imageListener, 0, 0, ImageView.ScaleType.CENTER_CROP);
}

進(jìn)行圖片緩存的類

/**
 * 圖片緩存
 *
 * @author JustDo23
 */
public class BitmapCache implements ImageLoader.ImageCache {

  private LruCache<String, Bitmap> cache;// 緩存圖片
  private int maxSize = 10 * 1024 * 1024;// 最大10MB

  /**
   * 構(gòu)造方法中實(shí)例化
   */
  public BitmapCache() {
    cache = new LruCache<String, Bitmap>(maxSize) {
      @Override
      protected int sizeOf(String key, Bitmap value) {
        return value.getRowBytes() * value.getHeight();
      }
    };
  }

  /**
   * 獲取圖片
   *
   * @param url 圖片 URL
   * @return 圖片 Bitmap
   */
  @Override
  public Bitmap getBitmap(String url) {
    return cache.get(url);
  }

  /**
   * 緩存圖片
   *
   * @param url 圖片 URL
   * @return 圖片 Bitmap
   */
  @Override
  public void putBitmap(String url, Bitmap bitmap) {
    cache.put(url, bitmap);
  }
}

方式二:使用 Volley 內(nèi)部封裝的顯示網(wǎng)絡(luò)圖片控件 NetworkImageView

niv_show = (NetworkImageView) findViewById(R.id.niv_show);

public void getNetImage() {
    String imageUrl = "http://img4.duitang.com/uploads/item/201509/30/20150930002351_3vHWx.thumb.700_0.jpeg";
    // [獲取一個(gè) ImageLoader 對象] 參數(shù):[請求隊(duì)列][圖片緩存對象]
    ImageLoader imageLoader = new ImageLoader(JustApplication.getRequestQueue(), new BitmapCache());
    // [設(shè)置默認(rèn)顯示圖片]
    niv_show.setDefaultImageResId(R.mipmap.ic_launcher);
    // [設(shè)置加載失敗顯示圖片]
    niv_show.setErrorImageResId(R.mipmap.ic_launcher);
    // [設(shè)置 URL 和 ImageLoader]
    niv_show.setImageUrl(imageUrl, imageLoader);
}

04. 自定義 Request

Android Volley完全解析(三),定制自己的Request

當(dāng) Volley 本身提供的請求不夠用的時(shí)候,可以參考 Volley 中請求的實(shí)現(xiàn)方式來進(jìn)行自定義。其中Request<T>帶泛型的請求基類。看下StringRequest的源碼

/**
 * A canned request for retrieving the response body at a given URL as a String.
 */
public class StringRequest extends Request<String> {
    private final Listener<String> mListener;

    /**
     * Creates a new request with the given method.
     *
     * @param method the request {@link Method} to use
     * @param url URL to fetch the string at
     * @param listener Listener to receive the String response
     * @param errorListener Error listener, or null to ignore errors
     */
    public StringRequest(int method, String url, Listener<String> listener,
            ErrorListener errorListener) {
        super(method, url, errorListener);
        mListener = listener;
    }

    /**
     * Creates a new GET request.
     *
     * @param url URL to fetch the string at
     * @param listener Listener to receive the String response
     * @param errorListener Error listener, or null to ignore errors
     */
    public StringRequest(String url, Listener<String> listener, ErrorListener errorListener) {
        this(Method.GET, url, listener, errorListener);
    }

    @Override
    protected void deliverResponse(String response) {
        mListener.onResponse(response);
    }

    @Override
    protected Response<String> parseNetworkResponse(NetworkResponse response) {
        String parsed;
        try {
            parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
        } catch (UnsupportedEncodingException e) {
            parsed = new String(response.data);
        }
        return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
    }
}

再此基礎(chǔ)上,編寫自定義的 Request

/**
 * 帶有 XML 解析的網(wǎng)絡(luò)請求
 *
 * @author JustDo23
 */
public class XMLRequest extends Request<XmlPullParser> {

  private final Response.Listener<XmlPullParser> mListener;// 網(wǎng)絡(luò)請求成功的回調(diào)

  /**
   * [必須有一個(gè)][構(gòu)造方法]
   *
   * @param method        請求方式
   * @param url           請求的網(wǎng)絡(luò)地址
   * @param listener      成功的回調(diào)
   * @param errorListener 失敗的回調(diào)
   */
  public XMLRequest(int method, String url, Response.Listener<XmlPullParser> listener, Response.ErrorListener errorListener) {
    super(method, url, errorListener);
    mListener = listener;
  }

  /**
   * 默認(rèn)的 GET 請求
   */
  public XMLRequest(String url, Response.Listener<XmlPullParser> listener, Response.ErrorListener errorListener) {
    this(Method.GET, url, listener, errorListener);
  }

  /**
   * [必須重寫][網(wǎng)絡(luò)請求返回?cái)?shù)據(jù)]
   *
   * @param response 網(wǎng)絡(luò)請求結(jié)果
   * @return 處理之后的數(shù)據(jù)
   */
  @Override
  protected Response<XmlPullParser> parseNetworkResponse(NetworkResponse response) {
    try {// 先獲取網(wǎng)絡(luò)返回是字符串再將字符串轉(zhuǎn)成流傳遞給解析器最后將解析器返回
      String xmlString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
      XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
      XmlPullParser xmlPullParser = factory.newPullParser();
      xmlPullParser.setInput(new StringReader(xmlString));
      return Response.success(xmlPullParser, HttpHeaderParser.parseCacheHeaders(response));
    } catch (UnsupportedEncodingException e) {
      return Response.error(new ParseError(e));
    } catch (XmlPullParserException e) {
      return Response.error(new ParseError(e));
    }
  }

  /**
   * [必須重寫][將parseNetworkResponse方法返回的數(shù)據(jù)返回給主線程]
   *
   * @param response
   */
  @Override
  protected void deliverResponse(XmlPullParser response) {
    mListener.onResponse(response);
  }

}

再利用 Gson 進(jìn)行封裝

/**
 * 帶有 Gson 解析的網(wǎng)絡(luò)請求
 *
 * @author JustDo23
 */
public class GsonRequest<T> extends Request<T> {

  private final Response.Listener<T> mListener;// 網(wǎng)絡(luò)請求成功的回調(diào)
  private Gson mGson;// Gson 對象
  private Class<T> mClass;// 解析后 JavaBean

  public GsonRequest(int method, String url, Class<T> clazz, Response.Listener<T> listener, Response.ErrorListener errorListener) {
    super(method, url, errorListener);
    mGson = new Gson();
    mClass = clazz;
    mListener = listener;
  }

  public GsonRequest(String url, Class<T> clazz, Response.Listener<T> listener, Response.ErrorListener errorListener) {
    this(Method.GET, url, clazz, listener, errorListener);
  }

  @Override
  protected Response<T> parseNetworkResponse(NetworkResponse response) {
    try {// 先獲取網(wǎng)絡(luò)請求返回的Json字符串,再利用Gson將字符串轉(zhuǎn)成對象
      String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
      return Response.success(mGson.fromJson(jsonString, mClass), HttpHeaderParser.parseCacheHeaders(response));
    } catch (UnsupportedEncodingException e) {
      return Response.error(new ParseError(e));
    }
  }

  @Override
  protected void deliverResponse(T response) {
    mListener.onResponse(response);
  }

}

05. 再度深入

Android Volley完全解析(四),帶你從源碼的角度理解Volley

全局維護(hù)一個(gè)隊(duì)列,根據(jù)手機(jī)版本的不同使用不用的HttpStack當(dāng)然也可以擴(kuò)展到使用OKHttp,首次初始化5個(gè)網(wǎng)絡(luò)請求線程,先初始化一個(gè)帶緩存的網(wǎng)絡(luò)請求線程,再初始化四個(gè)不帶緩存的網(wǎng)絡(luò)請求線程。默認(rèn)情況下,每條網(wǎng)絡(luò)請求都是可以進(jìn)行緩存的。獲取到緩存之后,還會(huì)判斷緩存是否已經(jīng)過期,過期則重新進(jìn)行網(wǎng)絡(luò)請求否則直接使用緩存。

06. Https

Android 網(wǎng)絡(luò)--我是怎么做的: Volley+OkHttp+Https

利用 Volley 實(shí)現(xiàn) Https 在網(wǎng)上大概就幾種方式:直接信任所有,跳過驗(yàn)證,拓展到 OKHttp 添加證書等等。這篇文章是在網(wǎng)絡(luò)上找的比較好的一篇。

使用自簽名的證書進(jìn)行操作,就會(huì)遇到這些比較復(fù)雜麻煩的問題,例如訪問12306網(wǎng)站。一般只要是使用CA證書認(rèn)證的網(wǎng)站,默認(rèn)都是信任的,直接就能進(jìn)行訪問的,比如https:www.baidu.com在 Volley 中同樣可以直接訪問不要考慮認(rèn)證的問題。由于iOS年底提交項(xiàng)目必須使用https所以接口面臨證書之類的問題,寶寶真是好害怕,一切都準(zhǔn)備就緒后,不料買了個(gè)CA 證書,結(jié)果問題簡單化。

證書操作

01. 將 CER 證書轉(zhuǎn)成 BKS

參考:http://blog.csdn.net/u010314594/article/details/50765534

工具: [ JCE Provider ] bcprov-jdk15on-155.jar http://www.bouncycastle.org/latest_releases.html 在網(wǎng)站下載到最新版。

命令:下載之后需要使用命令行進(jìn)行操作,這個(gè)命令比較多,而且不能有回車

keytool -importcert -v -trustcacerts -alias 位置1
-file 位置2
-keystore 位置3 -storetype BKS
-providerclass org.bouncycastle.jce.provider.BouncyCastleProvider
-providerpath 位置4
-storepass 位置5

解釋:

位置1:是個(gè)隨便取的別名,供keytool方便管理
位置2:cer或crt證書的全地址 
位置3:生成后bks文件的位置,建議寫全地址 
位置4:上面下載JCE Provider包的位置 
位置5:生成后證書的密碼,自己設(shè)置,需要在項(xiàng)目中使用,用于確保KeyStore文件本身安全

命令執(zhí)行之后,如果失敗會(huì)有報(bào)錯(cuò)提示,使用最新版本基本沒有問題。命令執(zhí)行成功,最后會(huì)有中文[是|否]的選擇,輸入[是]即可完成全部過程。命名要符號(hào) Java 命名規(guī)范。

// 個(gè)人操作命令
keytool -importcert -v -trustcacerts -alias test12306 -file /Users/just/Desktop/test12306/srca.cer -keystore /Users/just/Desktop/test12306/test12306.bks -storetype BKS -providerclass org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath /Users/just/Desktop/test12306/bcprov-jdk15on-155.jar  -storepass test12306

02. 提取 CER 證書字符串

命令:

keytool -printcert -rfc -file xxx.cer

命令行操作,證書文件路徑可全路徑,可在證書所在目錄執(zhí)行。

Demo 地址

下載

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,039評論 25 709
  • afinalAfinal是一個(gè)android的ioc,orm框架 https://github.com/yangf...
    passiontim閱讀 15,873評論 2 45
  • 每個(gè)星座都有影響自己一生的桃花弱點(diǎn),或明或暗。若不剖析、解決,一不小心就會(huì)在陰溝里打翻了愛情這艘華麗的船?,F(xiàn)在告訴...
    星座的這一些事閱讀 343評論 0 0
  • 說到貧窮,我首先想到了我自己,由于一貫對錢和消費(fèi)的保守思想,我過著大多數(shù)窮人的生活,害怕風(fēng)險(xiǎn),不敢投資,不會(huì)理財(cái),...
    浪跡天涯jjs閱讀 220評論 1 2
  • 忙碌的周二啊 回到家就什么也不想干 這樣的狀態(tài)不好啊 我把關(guān)于star staff的感想發(fā)給熊貓 她說 你這內(nèi)心活...
    角落蜷縮閱讀 160評論 0 0

友情鏈接更多精彩內(nèi)容