Android新的网络请求框架volley源码解释及示例

    最近遇到一个问题:我想用HttpClient来访问网络,发现怎么都无法new出HttpClient的对象,这我就有点摸不着头脑了。记得我之前都是可以使用这个类的,怎么突然间就用不了了。因为不知情,一下子就有点慌了。是我的写法不对?是Android studio开发工具出bug了?还是我的人品积累的不够?我想都没想,立即否定了第三点。(玩笑)
    后来到网上查了下资料,发现在最新的Android SDK中,这个类已经被移除了。就是说Google在最新的SDK中不再支持使用HttpClient来访问网络了。这里就告诉我们一个十分重要的道理:在开发项目的时候,我们要尽量的不用或者是少用那些已经过时了(deprecated)的方法了,因为在后来更新的SDK版本中,我们可能就没法使用某些被Google丢弃的封装类了,然后程序就会报错。像我遇到的httpclient这个类就无法使用的情况。还有一点就是我们要时刻关注Google对Android 像是开发工具和SDK的更新情况等,这是作为一名Android 开发人员应该有的修养---目光要在技术的前端。

   为什么HttpClient不可以使用了?这段时间里,到底发生了什么事?

   原来,之前我们使用的HttpURLConnection和HttpClient的用法还是挺复杂的,而且其中的API多,不易扩展,容易出bug,稍不注意就会写出不少重复代码和error。所以,在2013年Google I/O大会上推出了一个新的网络通信框架——Volley。这套框架主要是用于一些不是很大量但是很频繁的网络访问,对于有大量下载的网络访问,它就表现的不行不行的了,这个是要注意的地方。

   下面我们先开始来对volley作一个简单的介绍和简单的使用。

   一、下载volley 的jar包。

   这个jar包是开源的,网上一搜有大把,这里我提供一个下载的地址:点击打开链接    就可以下载了

   二、把volley包导入我们的项目中。

   copy到项目的libs目录下,右键--->add as libarary,最后ok。

   三、开始使用volley框架。

   在这里,我自己写了一个类,主要是用来使用volley几个常用的方法来访问网络,获取数据,以及每个方法的源码解释。


   先上效果截图:

      

以及两个图片加载的方法效果图

    


   然后,直接上代码吧,代码里面都有详细的解释了。

  先是布局代码:很简单的一个scrollview包含一个多个控件的linearlayout,因为要显示的内容比较长,所用要scrollview。

<span style="font-size:14px;"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="vertical">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <EditText
                android:id="@+id/ed_input"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:singleLine="true"
                android:text="https://www.baidu.com"
                android:textSize="20sp" />

            <Button
                android:id="@+id/btn_getdate"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="URLConnection方式获取网络数据" />

            <Button
                android:id="@+id/btn_volleyget"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="3dp"
                android:text="volley-GET方式获取网络数据" />

            <Button
                android:id="@+id/btn_volleypost"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="3dp"
                android:text="volley-POST方式获取网络数据" />

            <Button
                android:layout_marginTop="3dp"
                android:id="@+id/btn_volleyJSON_obj"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="volleyJSONobject获取网络object对象数据" />

            <Button
                android:id="@+id/btn_volleyJSON_arr"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="3dp"
                android:text="volley-JSONarray获取往array对象数据" />

            <Button
                android:id="@+id/btn_getimg"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="3dp"
                android:text="volley-ImageLoader加载图片" />

            <Button
                android:id="@+id/btn_NetworkImageView"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="3dp"
                android:text="volley-NetworkImageView加载图片" />

            <ImageView
                android:id="@+id/img_show1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:scaleType="fitCenter" />

            <ImageView
                android:id="@+id/img_show"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:scaleType="fitCenter" />

            <com.android.volley.toolbox.NetworkImageView
                android:id="@+id/networkImageView"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_centerHorizontal="true"
                android:layout_marginTop="10dp" />

            <TextView
                android:id="@+id/tv_show"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:gravity="center"
                android:text="@string/hello_world"
                android:textSize="20sp" />
        </LinearLayout>

    </ScrollView>


</LinearLayout></span>


   再然后是主要的java代码实现,里面有很详细的用法介绍和源码解释了,大家可以认真看看。

<span style="font-size:14px;">package com.yaojt.com.httptest;

import android.app.Activity;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.util.LruCache;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.TextView;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.ImageLoader;
import com.android.volley.toolbox.JsonArrayRequest;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.NetworkImageView;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;

public class MainActivity extends Activity {
    
    private TextView tv_show;
    private Button btn_getdate;
    private String URL = "https://www.baidu.com";
    private String URL1 = "http://m.weather.com";
    private EditText ed_input;
    private Button btn_volleyget;
    private Button btn_volleypost;
    private Button btn_volleyJSONobject, btn_volleyJSONarray;
    private Button btn_getimg;
    private ImageView img_show, img_show1;
    private Button btn_NetworkImageView;

    private HttpURLConnection conn;
    private RequestQueue requestQueue;

    private JsonObjectRequest jsonObjectRequest;
    private JsonArrayRequest jsonArrayRequest;
    private StringRequest requestPOST;
    private StringRequest requestGET;

    private NetworkImageView mNetworkImageView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        requestQueue = Volley.newRequestQueue(this); //一开始得到一个请求队列,主要是用于对网络请求的派件工作
        initViews();
        initListener();
    }


    /**
     * 初始化控件
     */
    private void initViews(){
        tv_show = (TextView) findViewById(R.id.tv_show);
        btn_getdate = (Button) findViewById(R.id.btn_getdate);
        ed_input = (EditText) findViewById(R.id.ed_input);
        btn_volleyget = (Button) findViewById(R.id.btn_volleyget);
        btn_volleypost = (Button) findViewById(R.id.btn_volleypost);
        btn_volleyJSONobject = (Button) findViewById(R.id.btn_volleyJSON_obj);
        btn_volleyJSONarray = (Button) findViewById(R.id.btn_volleyJSON_arr);
        btn_getimg = (Button) findViewById(R.id.btn_getimg);
        img_show = (ImageView) findViewById(R.id.img_show);
        img_show = (ImageView) this.findViewById(R.id.img_show);
        mNetworkImageView = (NetworkImageView) findViewById(R.id.networkImageView);
        btn_NetworkImageView = (Button) findViewById(R.id.btn_NetworkImageView);
        img_show1 = (ImageView) findViewById(R.id.img_show1);
    }

    /**
     * 初始化监听器
     */
    private void initListener(){
        btn_NetworkImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                NetworkImageViewGetImg(); //直接调用此方法,然后再布局中直接显示图片
            }
        });
        btn_getimg.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ImageLoaderGetImg();
            }
        });
        btn_volleyJSONarray.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                URL1 = ed_input.getText().toString().trim();
                volleyJSONarray();
            }
        });
        btn_volleyJSONobject.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                URL = ed_input.getText().toString().trim();
                volleyJSONobject();
            }
        });
        btn_volleypost.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                URL = ed_input.getText().toString().trim();
                volleyPOST();
            }
        });
        btn_volleyget.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                URL = ed_input.getText().toString().trim();
                volleyGET();
            }
        });
        btn_getdate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                URL = ed_input.getText().toString().trim();
                asynctaskLOAD(URL);
            }
        });
    }

    /**
     * 利用JsonObjectRequest来得到JSONObject对象
     *
     * Constructor which defaults to <code>GET</code> if <code>jsonRequest</code> is
     * <code>null</code>, <code>POST</code> otherwise.
     *
     * //@see #JsonObjectRequest(int, String, JSONObject, Response.Listener, Response.ErrorListener)
     * public JsonObjectRequest(String url, JSONObject jsonRequest, Response.Listener<JSONObject> listener,
         Response.ErrorListener errorListener) {
            this(jsonRequest == null ? Request.Method.GET : Request.Method.POST, url, jsonRequest, listener, errorListener); //可以看到源码
            //如果第二个参数传入的值!= null 的话,它会选择是post方式
        }
     */
    private void volleyJSONobject() {
        String url = "http://pipes.yahooapis.com/pipes/pipe.run?_id=giWz8Vc33BG6rQEQo_NLYQ&_render=json";
        jsonObjectRequest = new JsonObjectRequest(url, null, new Response.Listener<JSONObject>() { //这里传入null,会选择是get方式
            @Override
            public void onResponse(JSONObject response) {
                tv_show.setText("利用JsonObjectRequest得到的object对象为:" + response);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                tv_show.setText("===>>利用JsonObjectRequest访问网络错误,错误信息为:" + error);
            }
        });

        requestQueue.add(jsonObjectRequest);
    }

    /**
     * 利用JsonArrayRequest得到JSONArray对象
     *
     * 源码:
     * Creates a new request. 创建一个新的请求
     *
     * //@param url URL to fetch the JSON from
     * //@param listener Listener to receive the JSON response
     * //@param errorListener Error listener, or null to ignore errors.
     *public JsonArrayRequest(String url, Response.Listener<JSONArray> listener, Response.ErrorListener errorListener) {
            super(Request.Method.GET, url, null, listener, errorListener); //这里使用的是Request.Method.GET 方式
      }
     */
    private void volleyJSONarray() {
        jsonArrayRequest = new JsonArrayRequest(URL1, new Response.Listener<JSONArray>() { //它这里只有get方式
            @Override
            public void onResponse(JSONArray response) {
                tv_show.setText("利用volley-JsonArrayRequest方式获取的的网络数据为:" + response.toString());
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                //因为我这里没有一个返回jsonarrayrequest的接口,所以这里返回的数据老是提示错误
                tv_show.setText("利用volley-JsonArrayRequest方式访问错误,错误信息为:" + error);
            }
        });
        requestQueue.add(jsonArrayRequest); //将请求加入到请求队列中区
    }

    /**
     * 利用StringRequest得到String对象
     *
     * Creates a new request with the given method. 创建一个给定方式的请求
     *
     * //@param method the request {@link Request.Method} to use 参数一:请求方式get或者post
     * //@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, Response.Listener<String> listener,
            Response.ErrorListener errorListener) {
                super(method, url, errorListener);
                mListener = listener;
            }
     */
    private void volleyPOST() {
        requestPOST = new StringRequest(Request.Method.POST, URL, new Response.Listener<String>() { //指定为post方式
            @Override
            public void onResponse(String s) { //这里指定的是post方法
                tv_show.setText("利用volley--POST方式得到的网络数据:" + s);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                tv_show.setText("利用volley--POST方式访问网络错误,错误信息为:" + volleyError.toString());
            }
        });
        requestQueue.add(requestPOST); //最后要记得加入到请求队列中去
    }

    /**
     * 默认利用GET方式得到string对象
     * 看下面源码:
     *
     * Creates a new GET request. 创建一个新的get方式的请求
     *
     * //@param url URL to fetch the string at
     * //@param listener Listener to receive the String response 这个是Response接口类里面的Listener方法
     * //@param errorListener Error listener, or null to ignore errors 这个是Response接口类里面的ErrorListener方法
     * public StringRequest(String url, Response.Listener<String> listener, Response.ErrorListener errorListener) {
          this(Request.Method.GET, url, listener, errorListener); //这里是默认的get方式
       }
     */
    private void volleyGET() {
        requestGET = new StringRequest(URL, new Response.Listener<String>() { //这个是默认的利用get方式访问网络 看注释源码
            @Override
            public void onResponse(String s) { //源码中默认的是get的方式
                tv_show.setText("利用volley--GET方式得到的网络数据:" + s);
            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError volleyError) {
                tv_show.setText("利用volley--GET方式访问网络error,错误信息为:" + volleyError.toString());
            }
        });
        requestQueue.add(requestGET); //最后要记得加入到请求队列中去
    }

    /**
     * 利用AsyncTask异步任务来加载图片
     *
     * @param url
     */
    private void asynctaskLOAD(String url) {
        new AsyncTask<String, String, String>() { //new一个匿名异步任务类实例,参数一:传入值;参数二:过程传出值;参数三:结果返回值;
            @Override
            protected String doInBackground(String... params) {
                String str = "";
                try {
                    URL url = new URL(params[0]); //取得第一个参数URL地址
                    URLConnection connection = url.openConnection(); //打开连接
                    InputStream in = connection.getInputStream(); //得到输入流
                    InputStreamReader isr = new InputStreamReader(in, "utf-8"); //将输入流包装成字符流,并指定编码格式
                    BufferedReader br = new BufferedReader(isr);
                    String line;
                    while ((line = br.readLine()) != null) {
                        str += line;
                    }
                    br.close(); //这里要关闭流,是先打开后关闭
                    isr.close();
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return str; //这里是结果返回值
            }

            @Override
            protected void onPostExecute(String string) { //接收到结果返回值,并作处理
                tv_show.setText("利用AsyncTask异步任务方式得到的网络数据:" + string);
            }
        }.execute(url); //记得要执行,这个异步任务才会执行
    }

    /**
     * 利用ImageLoader来加载网络图片
     * getImageListener(ImageView view, int defaultImageResId, int errorImageResId) //这个方法就是传入一个请求队列和一个图片的缓存即可
     * 第一个参数:显示图片的ImageView
     * 第二个参数:默认显示的图片资源
     * 第三个参数:加载错误时显示的图片资源
     *
     * 我们关键来看看ImageListener getImageListener(final ImageView view,final int defaultImageResId, final int errorImageResId)这个方法是得到
     * 一个图片加载的监听器和两个回调函数
     * 看到第一个参数的解释:The imageView that the listener is associated with.和监听器关联的img,其实这个是你加载了的图片要显示的位置
     * 我们可以直接看到它的关键源码:
     * view.setImageResource(errorImageResId); //当错误时显示的图片,第三个参数
     * view.setImageBitmap(response.getBitmap()); //成功加载的图片显示
     * view.setImageResource(defaultImageResId); //在加载过程中显示的默认图片,代替失败或者是成功前的图片显示
     * 所以,我们只要将我们显示图片的控件传进去就可以了
     */
    //这里加载一张图片在imgv上显示
    public void ImageLoaderGetImg() {
        final LruCache<String, Bitmap> lruCache = new LruCache<String, Bitmap>(8); //缓存为8m
        //这里new一个缓存空间,也可以使用在最后面一个继承自ImageLoader.ImageCache的类来做,这里就不演示了
        ImageLoader imageLoader = new ImageLoader(requestQueue, new ImageLoader.ImageCache() { //传入网络请求队列和图片的缓存对象
            @Override
            public Bitmap getBitmap(String key) {
                return lruCache.get(key);
            } //将图片存储起来,下次运行时会优先选择在内存中是否有这个图片的缓存,有则直接读取出来,没有再到网上去取数据

            @Override
            public void putBitmap(String key, Bitmap bitmap) {
                lruCache.put(key, bitmap);
            }
        });
        String url = "http://e.hiphotos.baidu.com/image/pic/item/d0c8a786c9177f3e6bf9623a75cf3bc79f3d5633.jpg";
        ImageLoader.ImageListener listener = ImageLoader.getImageListener(img_show, R.drawable.imgv1, R.drawable.imgv2); //传入URL,默认图片和失败图片
        imageLoader.get(url, listener); //最后要运行调用get方法,传入url和监听器
        //指定图片允许的最大宽度和高度
//        imageLoader.get(url,listener, 200, 200);
    }

    /**
     *
     * 利用NetworkImageView显示网络图片,这里要在布局中创建一个com.android.volley.toolbox.NetworkImageView控件,看布局代码
     * 我们来看下setImageUrl这个方法的执行流程
     *
     * 方法的解释:给NetworkImageView这个控件设置一个给定URL路径的图片。
     * 此方法会立即在缓存中查找有无此图片;有则显示,没有则通过调用NetworkImageView
     * 方法显示一个默认加载图片并且去加载此图片。
     *
     * 在方法内部会调用
     * loadImageIfNecessary(false); // The URL has potentially changed. See if we need to load it.
     * 我们来走下这个方法:
     * 1、先得到此控件的宽高;如果宽高为0,则返回;
     * 2、判断传入url是否为空;为空则将请求取消,设置控件的图片为null,并返回;
     * 3、判断此控件的前一个请求是否要取消它(前提是有前一个请求),这里有两个情况:一、同一个
     * url请求,返回;二、不是同一个url请求,取消前一个请求,然后下一步;
     * 4、调用ImageContainer newContainer = ImageLoader.get()方法去加载新的url图片,new一个ImageListener图片监听方法,成功则显示
     * 加载的图片,不成功则加载错误显示的图片;(这里面还有一个布尔值参数isInLayoutPass = false
     * 重新开新线程去回调onRespose方法,默认是没有调用的);
     * 5、最后将控件的mImageContainer更新为新的newContainer ;
     *
     */
    //此方法是在布局的NetworkImageView控件上加载显示一张图片
    private void NetworkImageViewGetImg() {
        String imageUrl = "http://f.hiphotos.baidu.com/image/pic/item/c9fcc3cec3fdfc03777a357fd03f8794a5c226f3.jpg";
        final LruCache<String, Bitmap> lruCache = new LruCache<String, Bitmap>(8);
        ImageLoader.ImageCache imageCache = new ImageLoader.ImageCache() { //创建一个图片缓存实例
            @Override
            public void putBitmap(String key, Bitmap value) {
                lruCache.put(key, value);
            }
            @Override
            public Bitmap getBitmap(String key) {
                return lruCache.get(key);
            }
        };
        ImageLoader imageLoader = new ImageLoader(requestQueue, imageCache);
        mNetworkImageView.setTag("url");
        mNetworkImageView.setImageUrl(imageUrl, imageLoader);
    }

    /**
     * bitmap存储类,继承自ImageLoader.ImageCache。这里没有用到
     */
    private class BitmapCache implements ImageLoader.ImageCache {
        private LruCache<String, Bitmap> cache;

        public BitmapCache() {
            cache = new LruCache<String, Bitmap>(8 * 1024 * 1024) { //缓存空间为8m
                @Override
                protected int sizeOf(String key, Bitmap bitmap) {
                    return bitmap.getRowBytes() * bitmap.getHeight();
                }
            };
        }

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

        @Override
        public void putBitmap(String url, Bitmap bitmap) {
            cache.put(url, bitmap);
        }
    }

}</span>
   以上是volley框架的代码示例,比较长,但是是比较实用的。

   总的来讲,volley框架并不会很难懂,因为开发volley框架本来就是让大家的开发过程变得很简练简约。所以学习此框架还是很不错的。

   到此为止了,若哪里理解有偏差,请指教!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值