Volley框架浅析

Posted 劲火星空

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Volley框架浅析相关的知识,希望对你有一定的参考价值。

一、概念



什么是Volley

开发android应用很多时候都要涉及网络操作,Android SDK中提供了HttpClient 和 HttpUrlConnection两种方式用来处理网络操作,但当应用比较复杂的时候需要我们编写大量的代码处理很多东西:图像缓存,请求的调度等等;

而Volley框架就是为解决这些而生的,它与2013年Google I/O大会上被提出:使得Android应用网络操作更方便更快捷;抽象了底层Http Client等实现的细节,让开发者更专注与产生RESTful Request。另外,Volley在不同的线程上异步执行所有请求而避免了阻塞主线程。




二、特点

如下是Volley框架的内部实现原理图,蓝色是主线程,黄色是缓存线程,绿色是网络线程

    1. 自动调度网络请求
    2. 多个并发的网络连接
    3. 通过使用标准的HTTP缓存机制保持磁盘和内存响应的一致
    4. 支持请求优先级
    5. 支持取消请求的强大API,可以取消单个请求或多个
    6. 易于定制
    7. 健壮性:便于正确的更新UI和获取数据
    8. 包含调试和追踪工具

三、使用

1. 获得String数据
        volleybt.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                //新建请求队列
                RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this);

                //新建请求
                String url = "https://www.baidu.com/?tn=sitehao123_15";

                StringRequest request = new StringRequest(url, new Response.Listener<String>() 
                    @Override
                    public void onResponse(String s) 
                        volleytext.setText(s);
                    
                , new Response.ErrorListener() 
                    @Override
                    public void onErrorResponse(VolleyError volleyError) 
                        volleytext.setText("加载失败"+volleyError);
                    
                );

                requestQueue.add(request);
            
        );

2. 获得json数据
        json_bt.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                // 1 创建一个请求队列
                RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this);

                // 2 创建一个请求
                String url = "http://api.m.mtime.cn/PageSubArea/TrailerList.api";
                JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, null, new Response.Listener<JSONObject>() 
                    @Override
                    public void onResponse(JSONObject jsonObject) 
                        volleytext.setText(jsonObject.toString());
                    
                , new Response.ErrorListener() 
                    @Override
                    public void onErrorResponse(VolleyError volleyError) 
                        volleytext.setText("请求失败" + volleyError);
                    
                );

                // 3 将创建的请求添加到请求队列中
                requestQueue.add(jsonObjectRequest);
            
        );

3. post获得String数据
        post_bt.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                // 1 创建一个请求队列
                RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this);

                // 2 创建一个post请求
                String url = "http://api.m.mtime.cn/PageSubArea/TrailerList.api";
                StringRequest stringRequest = new StringRequest(Request.Method.POST, url, new Response.Listener<String>() 
                    @Override
                    public void onResponse(String s) 
                        volleytext.setText(s);
                    
                , new Response.ErrorListener() 
                    @Override
                    public void onErrorResponse(VolleyError volleyError) 
                        volleytext.setText("请求失败" + volleyError);
                    
                ) 

                ;

                // 3 将post请求添加到队列中
                requestQueue.add(stringRequest);
            
        );

4. 自定义获得xml数据
        xml_bt.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                // 1 创建一个请求队列
                RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this);
                XMLRequest xmlRequest = new XMLRequest(
                        "http://flash.weather.com.cn/wmaps/xml/china.xml",
                        new Response.Listener<XmlPullParser>() 
                            @Override
                            public void onResponse(XmlPullParser response) 
                                try 
                                    int eventType = response.getEventType();
                                    while (eventType != XmlPullParser.END_DOCUMENT) 
                                        switch (eventType) 
                                            case XmlPullParser.START_TAG:
                                                String nodeName = response.getName();
                                                if ("city".equals(nodeName)) 
                                                    String pName = response.getAttributeValue(0);
                                                    Log.d("TAG", "pName is " + pName);
                                                
                                                break;
                                        
                                        eventType = response.next();
                                    
                                 catch (XmlPullParserException e) 
                                    e.printStackTrace();
                                 catch (IOException e) 
                                    e.printStackTrace();
                                
                            
                        , new Response.ErrorListener() 
                    @Override
                    public void onErrorResponse(VolleyError error) 
                        Log.e("TAG", error.getMessage(), error);
                    
                );
                requestQueue.add(xmlRequest);
            
        );

需要重新一个xmlRequest继承Request
public class XMLRequest extends Request<XmlPullParser> 

    private final Response.Listener<XmlPullParser> mListener;

    public XMLRequest(int method, String url, Response.Listener<XmlPullParser> listener,
                      Response.ErrorListener errorListener) 
        super(method, url, errorListener);
        mListener = listener;
    

    public XMLRequest(String url, Response.Listener<XmlPullParser> listener, Response.ErrorListener errorListener) 
        this(Method.GET, url, listener, errorListener);
    

    @Override
    protected Response<XmlPullParser> parseNetworkResponse(NetworkResponse response) 
        try 
            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));
        
    

    @Override
    protected void deliverResponse(XmlPullParser response) 
        mListener.onResponse(response);
    


5. 自定义获得Gson解析后的数据
        gson_bt.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this);

                GsonRequest<Weather> gsonRequest = new GsonRequest<Weather>(
                        "http://www.weather.com.cn/data/sk/101010100.html", Weather.class,
                        new Response.Listener<Weather>() 
                            @Override
                            public void onResponse(Weather weather) 
                                WeatherInfo weatherInfo = weather.getWeatherinfo();
                                Log.d("TAG", "city is " + weatherInfo.getCity());
                                Log.d("TAG", "temp is " + weatherInfo.getTemp());
                                Log.d("TAG", "time is " + weatherInfo.getTime());
                            
                        , new Response.ErrorListener() 
                    @Override
                    public void onErrorResponse(VolleyError error) 
                        Log.e("TAG", error.getMessage(), error);
                    
                );
                requestQueue.add(gsonRequest);
            
        );

同样需要定义一个GsonRequest继承Request
public class GsonRequest<T> extends Request<T> 

    private final Response.Listener<T> mListener;

    private Gson mGson;

    private Class<T> mClass;

    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 
            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);
    



//用于解析的类
class Weather 

    private WeatherInfo weatherinfo;

    public WeatherInfo getWeatherinfo() 
        return weatherinfo;
    

    public void setWeatherinfo(WeatherInfo weatherinfo) 
        this.weatherinfo = weatherinfo;
    



还需要一个WeatherInfo类来解析Gson
public class WeatherInfo 

    private String city;

    private String temp;

    private String time;

    public String getCity() 
        return city;
    

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

    public String getTemp() 
        return temp;
    

    public void setTemp(String temp) 
        this.temp = temp;
    

    public String getTime() 
        return time;
    

    public void setTime(String time) 
        this.time = time;
    



四、原理

首先来梳理一下整体的流程,先建立也队列,根据不同的系统版本建立不同的网络初始化,接下来在这个队列 中建立一个缓存进程和四个网络进程,一共是五个进程,然后在就是往这个队列中添加任务来。如果得到的请求有缓存资源就可以进行通过缓存线程执行任务了,如果没有缓存就加入到网路线程任务中,处理完成后将response发送出去,我们在回调函数中就可以得到结果了。

(一)队列创建

(1)网络的选择,是选择HttpStack还是HttpClientStack

    public static RequestQueue newRequestQueue(Context context, HttpStack stack)   
        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   
                stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent));  
              
          
        Network network = new BasicNetwork(stack);  
        RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);  
        queue.start();  
        return queue;  
      


(2)建立一个缓存线程和四个网络线程


    public void start()   
        stop();  // Make sure any currently running dispatchers are stopped.  
        // Create the cache dispatcher and start it.  
        mCacheDispatcher = new CacheDispatcher(mCacheQueue, mNetworkQueue, mCache, mDelivery);  
        mCacheDispatcher.start();  
        // Create network dispatchers (and corresponding threads) up to the pool size.  
        for (int i = 0; i < mDispatchers.length; i++)   
            NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,  
                    mCache, mDelivery);  
            mDispatchers[i] = networkDispatcher;  
            networkDispatcher.start();  
          
      


(二)增加请求


(1)加入队列中

    public <T> Request<T> add(Request<T> request)   
        // Tag the request as belonging to this queue and add it to the set of current requests.  
        request.setRequestQueue(this);  
        synchronized (mCurrentRequests)   
            mCurrentRequests.add(request);  
          
        // Process requests in the order they are added.  
        request.setSequence(getSequenceNumber());  
        request.addMarker("add-to-queue");  
        // If the request is uncacheable, skip the cache queue and go straight to the network.  
        if (!request.shouldCache())   
            mNetworkQueue.add(request);  
            return request;  
          
        // Insert request into stage if there's already a request with the same cache key in flight.  
        synchronized (mWaitingRequests)   
            String cacheKey = request.getCacheKey();  
            if (mWaitingRequests.containsKey(cacheKey))   
                // There is already a request in flight. Queue up.  
                Queue<Request<?>> stagedRequests = mWaitingRequests.get(cacheKey);  
                if (stagedRequests == null)   
                    stagedRequests = new LinkedList<Request<?>>();  
                  
                stagedRequests.add(request);  
                mWaitingRequests.put(cacheKey, stagedRequests);  
                if (VolleyLog.DEBUG)   
                    VolleyLog.v("Request for cacheKey=%s is in flight, putting on hold.", cacheKey);  
                  
             else   
                // Insert 'null' queue for this cacheKey, indicating there is now a request in  
                // flight.  
                mWaitingRequests.put(cacheKey, null);  
                mCacheQueue.add(request);  
              
            return request;  
          
      

(2)通过while循环的方式进行相应,如果缓存为空就加入到网络线程中

    public class CacheDispatcher extends Thread   
      
        ……  
      
        @Override  
        public void run()   
            if (DEBUG) VolleyLog.v("start new dispatcher");  
            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);  
            // Make a blocking call to initialize the cache.  
            mCache.initialize();  
            while (true)   
                try   
                    // Get a request from the cache triage queue, blocking until  
                    // at least one is available.  
                    final Request<?> request = mCacheQueue.take();  
                    request.addMarker("cache-queue-take");  
                    // If the request has been canceled, don't bother dispatching it.  
                    if (request.isCanceled())   
                        request.finish("cache-discard-canceled");  
                        continue;  
                      
                    // Attempt to retrieve this item from cache.  
                    Cache.Entry entry = mCache.get(request.getCacheKey());  
                    if (entry == null)   
                        request.addMarker("cache-miss");  
                        // Cache miss; send off to the network dispatcher.  
                        mNetworkQueue.put(request);  
                        continue;  
                      
                    // If it is completely expired, just send it to the network.  
                    if (entry.isExpired())   
                        request.addMarker("cache-hit-expired");  
                        request.setCacheEntry(entry);  
                        mNetworkQueue.put(request);  
                        continue;  
                      
                    // We have a cache hit; parse its data for delivery back to the request.  
                    request.addMarker("cache-hit");  
                    Response<?> response = request.parseNetworkResponse(  
                            new NetworkResponse(entry.data, entry.responseHeaders));  
                    request.addMarker("cache-hit-parsed");  
                    if (!entry.refreshNeeded())   
                        // Completely unexpired cache hit. Just deliver the response.  
                        mDelivery.postResponse(request, response);  
                     else   
                        // Soft-expired cache hit. We can deliver the cached response,  
                        // but we need to also send the request to the network for  
                        // refreshing.  
                        request.addMarker("cache-hit-refresh-needed");  
                        request.setCacheEntry(entry);  
                        // Mark the response as intermediate.  
                        response.intermediate = true;  
                        // Post the intermediate response back to the user and have  
                        // the delivery then forward the request along to the network.  
                        mDelivery.postResponse(request, response, new Runnable()   
                            @Override  
                            public void run()   
                                try   
                                    mNetworkQueue.put(request);  
                                 catch (InterruptedException e)   
                                    // Not much we can do about this.  
                                  
                              
                        );  
                      
                 catch (InterruptedException e)   
                    // We may have been interrupted because it was time to quit.  
                    if (mQuit)   
                        return;  
                      
                    continue;  
                  
              
          
      

(3)最后进行事件的分发





尊重作者,尊重原创,参考文章:


http://blog.csdn.net/guolin_blog/article/details/17656437

http://www.cnblogs.com/zyw-205520/p/4950357.html



















以上是关于Volley框架浅析的主要内容,如果未能解决你的问题,请参考以下文章

安卓中自定义并使用Volley框架请求网络

Volley框架源代码分析

Volley框架简介

Android Volley框架的使用

Volley框架模式

Volley框架的原理剖析-->