Volley網(wǎng)絡(luò)請(qǐng)求框架使用

一、前言:

Volley是Google官方出的一套小而巧的異步請(qǐng)求庫(kù),該框架封裝的擴(kuò)展性很強(qiáng),支持HttpClient、HttpUrlConnection,甚至支持OkHttp,而且Volley里面也封裝了ImageLoader,所以如果你愿意你甚至不需要使用圖片加載框架,不過這塊功能沒有一些專門的圖片加載框架強(qiáng)大,對(duì)于簡(jiǎn)單的需求可以使用,對(duì)于稍復(fù)雜點(diǎn)的需求還是需要用到專門的圖片加載框架。

Volley也有缺陷,比如不支持post大數(shù)據(jù),所以不適合上傳文件。不過Volley設(shè)計(jì)的初衷本身也就是為頻繁的、數(shù)據(jù)量小的網(wǎng)絡(luò)請(qǐng)求而生!

1. Volley網(wǎng)絡(luò)請(qǐng)求隊(duì)列

Volley 請(qǐng)求網(wǎng)絡(luò)都是基于請(qǐng)求隊(duì)列的,開發(fā)者只要把請(qǐng)求放在請(qǐng)求隊(duì)列中就可以了,請(qǐng)求隊(duì)列會(huì)依次進(jìn)行請(qǐng)求。一般情況下,一個(gè)應(yīng)用程序如果網(wǎng)絡(luò)請(qǐng)求不是特別的頻繁,完全可以只有一個(gè)請(qǐng)求隊(duì)列(對(duì)應(yīng) Application);如果網(wǎng)絡(luò)請(qǐng)求非常多或者有其他情況,則可以是一個(gè) Activity 對(duì)應(yīng)一個(gè)網(wǎng)絡(luò)請(qǐng)求隊(duì)列,這就要看具體情況了。

示例:

RequestQueue queue = Volley.newRequestQueue(getApplicationContext());

網(wǎng)絡(luò)請(qǐng)求權(quán)限一定不要忘記:

 <uses-permission android:name="android.permission.INTERNET"/>

二、 基本使用:

1.volley依賴

 //volley依賴
implementation 'com.mcxiaoke.volley:library:1.0.19'
 //gson依賴
compile 'com.google.code.gson:gson:2.7'
//butterknife,配置下面 兩行
implementation 'com.jakewharton:butterknife:8.5.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1'

2.RequestQueue在 Application 中初始化一次

public class MyApplication extends Application {
    public static RequestQueue queue;


    @Override
    public void onCreate() {
        super.onCreate();
        queue = Volley.newRequestQueue(getApplicationContext());
    }

    /**
     * 提供全局變量,如果使用 VolleyUtils 類,這里就不用寫了
     * 創(chuàng)建請(qǐng)求隊(duì)列對(duì)象,通常情況下,一個(gè)類中(或者說一個(gè)工程中)保持 始終使用同一個(gè)RequestQueue對(duì)象即可
     * @return
     */
    public static RequestQueue getHttpQueues() {
        return queue;
    }
}

3. StringRequest 中GET 請(qǐng)求

    /**
     * get 請(qǐng)求
     */
    private void getRequest() {

        String url = "http://apis.juhe.cn/mobile/get?phone=18856907654&key=5778e9d9cf089fc3b093b162036fc0e1";


        /**
         * 1. int 類型 用于指定請(qǐng)求的方式(如GET或者POST)
         * 2. String類型 用于指定網(wǎng)絡(luò)請(qǐng)求要連接的網(wǎng)址
         * 3. Listener類型 ,接收網(wǎng)絡(luò)響應(yīng)的接口,即只要得到本次請(qǐng)求對(duì)應(yīng)的返回結(jié)果
         * 就會(huì)運(yùn)行此接口中的onResponse方法
         * 4: ErrorListener類型, 用于接收當(dāng)網(wǎng)絡(luò)請(qǐng)求的過程中一旦發(fā)生了什么錯(cuò)誤,
         * 就會(huì)調(diào)用本接口中的onErrorResponse方法
         * */
        StringRequest stringRequest = new StringRequest(StringRequest.Method.GET, url, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                Log.d("LUO", "========" + response);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.d("LUO", "========" + error.getMessage());
            }
        });

        //三,給請(qǐng)求對(duì)象設(shè)置tag標(biāo)識(shí)
        stringRequest.setTag("get");
        //四,將請(qǐng)求添加到請(qǐng)求隊(duì)列中,執(zhí)行網(wǎng)絡(luò)請(qǐng)求
        MyApplication.getHttpQueues().add(stringRequest);
       //不要調(diào)用,看下方注意
        //MyApplication.getHttpQueues().start();
    }

注意:

//MyApplication.getHttpQueues().start();
建議不要手動(dòng)調(diào)用 RequestQueue 的 start() 方法,引起的問題“經(jīng)常會(huì)報(bào)com.android.volley.NoConnectionError: java.io.InterruptedIOException”,然后就內(nèi)容加載失敗。。。

因?yàn)樵?Volley.newRequestQueue() 方法中,已經(jīng)調(diào)用了 start() 方法。

看源碼示例:

public static RequestQueue newRequestQueue(Context context, HttpStack stack, int maxDiskCacheBytes) {
        File cacheDir = new File(context.getCacheDir(), DEFAULT_CACHE_DIR);

        String userAgent = "volley/0";
        try {
            String packageName = context.getPackageName();
            PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0);
            userAgent = packageName + "/" + info.versionCode;
        } catch (NameNotFoundException e) {
        }

        if (stack == null) {
            if (Build.VERSION.SDK_INT >= 9) {
                stack = new HurlStack();
            } else {
                // Prior to Gingerbread, HttpUrlConnection was unreliable.
                // See: http://android-developers.blogspot.com/2011/09/androids-http-clients.html
                stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));
            }
        }

        Network network = new BasicNetwork(stack);
        
        RequestQueue queue;
        if (maxDiskCacheBytes <= -1)
        {
            // No maximum size specified
            queue = new RequestQueue(new DiskBasedCache(cacheDir), network);
        }
        else
        {
            // Disk cache size specified
            queue = new RequestQueue(new DiskBasedCache(cacheDir, maxDiskCacheBytes), network);
        }
        //這里已經(jīng)啟動(dòng)了,不需要請(qǐng)求中再次調(diào)用
        queue.start();

        return queue;
    }

3. StringRequest 中 POST請(qǐng)求

 /**
     * post 請(qǐng)求
     */
    private void postRequest() {

        RequestQueue queue = Volley.newRequestQueue(this);
        String postUrl = "http://apis.juhe.cn/mobile/get";

        StringRequest stringRequest = new StringRequest(StringRequest.Method.POST, postUrl, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                Log.d("LUO", "========" + response);

            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.d("LUO", "========" + error.getMessage());
            }
        }) {
            /**
             * Post請(qǐng)求和Get請(qǐng)求的使用步驟上的區(qū)別在于請(qǐng)求條件的指定
             * 必須在StringRequest對(duì)象的后面添加{},并且
             * 在{}內(nèi)重寫getParams方法,該方法的返回值就是所有的請(qǐng)求條件
             * */
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                //將請(qǐng)求條件封裝到map對(duì)象中
                Map<String, String> map = new HashMap<>();
                map.put("phone", "18856907654");
                map.put("key", "5778e9d9cf089fc3b093b162036fc0e1");
                return map;
            }
        };

        //三,給請(qǐng)求對(duì)象設(shè)置tag標(biāo)識(shí)
        stringRequest.setTag("get");
        //四,將請(qǐng)求添加到請(qǐng)求隊(duì)列中,執(zhí)行網(wǎng)絡(luò)請(qǐng)求
        MyApplication.getHttpQueues().add(stringRequest);
    }

4.JSONObject網(wǎng)絡(luò)請(qǐng)求

 private void jsonRequest() {
        String postUrl = "http://apis.juhe.cn/mobile/get";
        Map<String, String> map = new HashMap<>();
        map.put("phone", "18856907654");
        map.put("key", "5778e9d9cf089fc3b093b162036fc0e1");

        String json = new Gson().toJson(map);
        JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST,
                postUrl,json, new Response.Listener<JSONObject>() {
            @Override
            public void onResponse(JSONObject response) {
                Log.d("LUO", "========" + response);
            }
        },new Response.ErrorListener(){

            @Override
            public void onErrorResponse(VolleyError error) {
                Log.d("LUO", "========" + error.getMessage());
            }
        });

        MyApplication.getHttpQueues().add(jsonObjectRequest);
    }

5.下載單張圖片

/**
     * 下載單張圖片
     */
    private void singlePhoto() {

        ImageRequest imageRequest = new ImageRequest(
                "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=2019270811,1269730008&fm=27&gp=0.jpg", //對(duì)應(yīng)圖片的下載地址
                new Response.Listener<Bitmap>() {
                    @Override
                    public void onResponse(Bitmap response) {
                        Log.d("LUO", "========" + response);
                        ivIcon.setImageBitmap(response);
                    }
                }, 200, 200,// 指定下載后圖片的最大寬高
                ImageView.ScaleType.FIT_XY,//指定圖片的縮放模式
                Bitmap.Config.ARGB_8888,//指定圖片的編碼格式
                new Response.ErrorListener() {
                    @Override
                    public void onErrorResponse(VolleyError error) {
                        Log.d("LUO", "========" + error.getMessage());
                    }
                });
        MyApplication.getHttpQueues().add(imageRequest);
    }

6.與Avctivity生命周期聯(lián)動(dòng)(注意啊)

其實(shí)就是在Activity退出時(shí)候或銷毀時(shí)候,取消對(duì)應(yīng)的網(wǎng)絡(luò)請(qǐng)求,避免網(wǎng)絡(luò)請(qǐng)求在后臺(tái)浪費(fèi)資源,所以,我們一般在onStop()方法中通過之前設(shè)置的Tag取消網(wǎng)絡(luò)請(qǐng)求:

 @Override
    protected void onDestroy() {
        super.onDestroy();
        //通過Tag標(biāo)簽取消請(qǐng)求隊(duì)列中對(duì)應(yīng)的全部請(qǐng)求
        MyApplication.getHttpQueues().cancelAll(tag);
    }

三、封裝使用:

1.VolleyUtils類

public class VolleyUtils {
    private static RequestQueue mQueue;
    private ImageLoader mLoader;
    private ImageLoader.ImageCache mCache;
    private static VolleyUtils mInstance;

    /**
     * 1.構(gòu)造方法私有化
     * @param context
     */
    private VolleyUtils(Context context) {
        //做一些事情
        mQueue = Volley.newRequestQueue(context);
        mCache = new MyImageCache();
        mLoader = new ImageLoader(mQueue, mCache);
    }

    public RequestQueue getQueue() {
        return mQueue;
    }

    public ImageLoader getLoader() {
        return mLoader;
    }


    /**
     * 2.提供一個(gè)靜態(tài)方法,返回一個(gè)當(dāng)前類
     * @param context
     * @return
     */
    public static VolleyUtils create(Context context) {
        if (mInstance == null) {
            synchronized (VolleyUtils.class) {
                if (mInstance == null) {
                    mInstance = new VolleyUtils(context);
                }
            }
        }
        return mInstance;
    }


    public <T> void get(String url, final Class<T> clazz, final OnResponse<T> listener) {

        HashMap<String, String> map = new HashMap<>();
        listener.OnMap(map);
        String param = prepareParam(map);
        if (param.trim().length() >= 1) {
            url += "?" + param;
        }
        Log.e("Volley", "urlResult---->" + url);
        StringRequest stringRequest = new StringRequest(StringRequest.Method.GET, url, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                Log.e("Volley", "response-->" + response);
                Gson gson = new Gson();
                listener.onSuccess(gson.fromJson(response, clazz));
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e("Volley", "response-->" + error.getMessage());
                listener.onError(error.getMessage());
            }
        });

        mQueue.add(stringRequest);
    }


    private static String prepareParam(Map<String, String> paramMap) {
        StringBuilder sb = new StringBuilder();
        if (paramMap.isEmpty()) {
            return "";
        } else {
            for (String key : paramMap.keySet()) {
                String value =  paramMap.get(key);
                if (sb.length() < 1) {
                    sb.append(key).append("=").append(value);
                } else {
                    sb.append("&").append(key).append("=").append(value);
                }
            }
            return sb.toString();
        }
    }


    public <T> void post(String url, final Class<T> clazz, final OnResponse<T> listener) {
        StringRequest stringRequest = new StringRequest(StringRequest.Method.POST, url, new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                Log.e("Volley", "response-->" + response);
                Gson gson = new Gson();
                listener.onSuccess(gson.fromJson(response, clazz));
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e("Volley", "response-->" + error.getMessage());
                listener.onError(error.getMessage());
            }
        }) {
            /**
             * Post請(qǐng)求和Get請(qǐng)求的使用步驟上的區(qū)別在于請(qǐng)求條件的指定
             * 必須在StringRequest對(duì)象的后面添加{},并且
             * 在{}內(nèi)重寫getParams方法,該方法的返回值就是所有的請(qǐng)求條件
             * */
            @Override
            protected Map<String, String> getParams() throws AuthFailureError {
                //將請(qǐng)求條件封裝到map對(duì)象中
                Map<String, String> map = new HashMap<>();
                listener.OnMap(map);
                return map;
            }
        };
        mQueue.add(stringRequest);
    }


    public void loadImg(String url, ImageView view, int maxWidth, int maxHeight, int defaultImageResId, int errorImageResId) {
        mLoader.get(url, //圖片的下載路徑
                /**
                 * 通過getImageListener方法獲取ImageListener接口對(duì)象
                 * 參數(shù)1: 圖片下載完成后,由哪個(gè)控件顯示圖片
                 * 參數(shù)2: 設(shè)置圖片下載過程中顯示的默認(rèn)圖片
                 * 參數(shù)3: 設(shè)置一旦圖片下載出錯(cuò),就顯示出錯(cuò)提示圖片
                 * */
                ImageLoader.getImageListener(view, defaultImageResId, errorImageResId),
                maxWidth, maxHeight, //圖片的最大寬高 指定成0的話就表示不管圖片有多大
                ImageView.ScaleType.FIT_XY //圖片的縮放模式
        );
    }

    public void loadImg(String url, ImageView view) {
        mLoader.get(url, //圖片的下載路徑
                ImageLoader.getImageListener(view, R.mipmap.ic_launcher, R.mipmap.ic_launcher),
                0, 0, //圖片的最大寬高 指定成0的話就表示不管圖片有多大
                ImageView.ScaleType.FIT_XY //圖片的縮放模式
        );
    }

    public void loadImg(String url, ImageView view, int defaultImageResId, int errorImageResId) {
        mLoader.get(url, //圖片的下載路徑
                ImageLoader.getImageListener(view, defaultImageResId, errorImageResId),
                0, 0, //圖片的最大寬高 指定成0的話就表示不管圖片有多大
                ImageView.ScaleType.FIT_XY //圖片的縮放模式
        );
    }

    /**
     * 分配一定內(nèi)存空間,專門存取圖片,一般為內(nèi)存大小的1/8
     */
    private class MyImageCache implements ImageLoader.ImageCache {

        private LruCache<String, Bitmap> mCache;

        private MyImageCache() {
            //分配最大內(nèi)存空間的1/8
            long maxMemory = Runtime.getRuntime().maxMemory() / 8;
            mCache = new LruCache<String, Bitmap>((int) maxMemory) {
                @Override
                protected int sizeOf(String key, Bitmap value) {
                    //得到當(dāng)前圖片的大小
                    return value.getByteCount();
                }
            };
        }

        @Override
        public Bitmap getBitmap(String url) {
            return mCache.get(url);
        }

        @Override
        public void putBitmap(String url, Bitmap bitmap) {
            if (getBitmap(url) == null)
                mCache.put(url, bitmap);
        }
    }

    /**
     * 自定義的類型
     * @param <T>
     */
    public class GsonRequest<T> extends Request<T> {
        private Response.Listener<T> mListener;
        private Gson mGson;
        private Class<T> mClazz;

        private GsonRequest(int method, String url, Response.Listener<T> listener, Response.ErrorListener errorListenerlistener, Class<T> clazz) {
            super(method, url, errorListenerlistener);
            this.mListener = listener;
            mGson = new Gson();
            this.mClazz = clazz;
        }

        @Override
        protected Response<T> parseNetworkResponse(NetworkResponse response) {
            String parsed;
            try {
                parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
                Log.e("Volley", "服務(wù)器返回JSON------>" + parsed);
                return Response.success(mGson.fromJson(parsed, mClazz), HttpHeaderParser.parseCacheHeaders(response));
            } catch (UnsupportedEncodingException e) {
                return Response.error(new VolleyError(e));
            }
        }

        @Override
        protected void deliverResponse(T response) {
            if (mListener != null) {
                mListener.onResponse(response);
            }
        }

        @Override
        protected void onFinish() {
            super.onFinish();
            mListener = null;
        }
    }

    public interface OnResponse<T> {

        void OnMap(Map<String, String> map);

        void onSuccess(T response);

        void onError(String error);
    }
}

2.PhoneBean類

public class PhoneBean {

    /**
     * resultcode : 200
     * reason : Return Successd!
     * result : {"province":"安徽","city":"合肥","areacode":"0551","zip":"230000","company":"移動(dòng)","card":""}
     * error_code : 0
     */

    private String resultcode;
    private String reason;
    private ResultBean result;
    private int error_code;

    public String getResultcode() {
        return resultcode;
    }

    public void setResultcode(String resultcode) {
        this.resultcode = resultcode;
    }

    public String getReason() {
        return reason;
    }

    public void setReason(String reason) {
        this.reason = reason;
    }

    public ResultBean getResult() {
        return result;
    }

    public void setResult(ResultBean result) {
        this.result = result;
    }

    public int getError_code() {
        return error_code;
    }

    public void setError_code(int error_code) {
        this.error_code = error_code;
    }

    public static class ResultBean {
        /**
         * province : 安徽
         * city : 合肥
         * areacode : 0551
         * zip : 230000
         * company : 移動(dòng)
         * card :
         */

        private String province;
        private String city;
        private String areacode;
        private String zip;
        private String company;
        private String card;

        public String getProvince() {
            return province;
        }

        public void setProvince(String province) {
            this.province = province;
        }

        public String getCity() {
            return city;
        }

        public void setCity(String city) {
            this.city = city;
        }

        public String getAreacode() {
            return areacode;
        }

        public void setAreacode(String areacode) {
            this.areacode = areacode;
        }

        public String getZip() {
            return zip;
        }

        public void setZip(String zip) {
            this.zip = zip;
        }

        public String getCompany() {
            return company;
        }

        public void setCompany(String company) {
            this.company = company;
        }

        public String getCard() {
            return card;
        }

        public void setCard(String card) {
            this.card = card;
        }
    }
}

3.直接調(diào)用:

public class TwoActivity extends Activity{

    private ImageView img;
    String urlStr = "http://apis.juhe.cn/mobile/get";

    String imgUrl = "https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=1263067444,118499721&fm=27&gp=0.jpg";
    private TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_two);
        img = findViewById(R.id.img);
        textView = findViewById(R.id.text);
    }

    public void btnGet(View view) {

        VolleyUtils.create(this)
                .get(urlStr, PhoneBean.class, new VolleyUtils.OnResponse<PhoneBean>() {
                    @Override
                    public void OnMap(Map<String, String> map) {
                        map.put("phone", "18856907654");
                        map.put("key", "5778e9d9cf089fc3b093b162036fc0e1");
                    }

                    @Override
                    public void onSuccess(PhoneBean response) {
                        Log.e("TAG", "response---->" + response);
                        textView.setText("get  :" + response.getResultcode() + " " + response.getResult().getCity());
                    }

                    @Override
                    public void onError(String error) {
                        Log.e("TAG", "error---->" + error);
                        textView.setText("error--->" + error);
                    }
                });
    }

    public void btnPost(View view) {
        VolleyUtils.create(this)
                .post(urlStr, PhoneBean.class, new VolleyUtils.OnResponse<PhoneBean>() {
                    @Override
                    public void OnMap(Map<String, String> map) {
                        map.put("phone", "18856907654");
                        map.put("key", "5778e9d9cf089fc3b093b162036fc0e1");
                    }

                    @Override
                    public void onSuccess(PhoneBean response) {
                        Log.e("TAG", "response---->" + response);
                        textView.setText("post  :" + response.getResultcode() + " " + response.getResult().getCity());
                    }

                    @Override
                    public void onError(String error) {
                        Log.e("TAG", "error---->" + error);
                        textView.setText("error--->" + error);
                    }
                });
    }

    public void btnImg(View view) {
        VolleyUtils.create(this)
                .loadImg(imgUrl, img);

//        VolleyUtils.create(this)
//                .loadImg(imgUrl,img,200,200,R.mipmap.ic_launcher,R.mipmap.ic_launcher);
//
//        VolleyUtils.create(this)
//                .loadImg(imgUrl,img,R.mipmap.ic_launcher,R.mipmap.ic_launcher);
    }

    public static void launch(Context mContext) {
        Intent intent = new Intent(mContext,TwoActivity.class);
        mContext.startActivity(intent);
    }
}

GitHub地址:

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

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