美文网首页
Volley+OkHttp学习笔记

Volley+OkHttp学习笔记

作者: qiying | 来源:发表于2016-07-21 18:46 被阅读100次

    OkHttp支持 Http1.0/1.1/2/0、SPDY协议,用来进行客户端和服务器的连接以及数据交互,扮演着传输层的角色。Volley负责处理请求,加载,缓存,线程,同步等问题。先来简单说下Volley的上层部分。用Volley进行网络请求的调用方式如下:

    RequestQueue mQueue = Volley.newRequestQueue(Context);
    mQueue.start();
    StringRequest stringRequest = new StringRequest(...);
    mQueue.add(stringRequest);
    //添加请求
    

    下面来看一下Volley的部分源码

    public static RequestQueue newRequestQueue(Context context, HttpStack stack) { 
      File cacheDir = new File(context.getCacheDir(), "volley"); 
      String userAgent = "volley/0"; 
      try { 
        String network = context.getPackageName(); 
        PackageInfo queue = context.getPackageManager().getPackageInfo(network, 0);
        userAgent = network + "/" + queue.versionCode; 
      } catch (NameNotFoundException var6) { 
        ; 
      }
      if(stack == null) { 
        if(VERSION.SDK_INT >= 9) { 
          stack = new HurlStack(); 
        } else { 
          stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); 
        } 
      } 
      //由此可见Volley支持自定义网络请求,继承HttpStack即可。Volley+OkHttp整合就是这样的 
      BasicNetwork network1 = new BasicNetwork((HttpStack)stack);  
      RequestQueue queue1 = new RequestQueue(new DiskBasedCache(cacheDir), network1); 
      queue1.start(); 
      return queue1;
    }
    

    所有的网络请求都是通过添加到请求队列RequestQueue来执行的,那么RequestQueue执行网络请求的原理又是什么呢?

    //线程安全的加减操作
    private AtomicInteger mSequenceGenerator;
    //等候缓存队列 key->url 如果我们有多个请求的url都是相同的,也就是说请求的资源是相同的,volley就把这些请求放入一个队列,
    //在用url做key将队列放入map中。
    private final Map<String, Queue<Request<?>>> mWaitingRequests;
    //所有在队列中,或者正在被处理的请求都会在这个集合中//缓存队列与网络队列的总和
    private final Set<Request<?>> mCurrentRequests;
    //缓存请求队列 有阻塞功能//阻塞功能的本质是读取队列中元素调用take()方法中:读写锁,若返回请求为空阻塞线程,直到
    //request不为空 返回request,先进先出 PriorityBlockingQueue添加了Lock锁
    private final PriorityBlockingQueue<Request<?>> mCacheQueue;
    //请求为从网络中直接获取的队列 有阻塞功能
    private final PriorityBlockingQueue<Request<?>> mNetworkQueue;
    //默认用于网络调度的线程池数目
    private static final int DEFAULT_NETWORK_THREAD_POOL_SIZE = 4;
    //缓存
    private final Cache mCache;
    //执行请求的网络
    private final Network mNetwork;
    //派发请求结果的接口,通过Handler向主线程发送消息private final ResponseDelivery mDelivery;
    //该队列的所有网络调度器 多个线程 全部开启 extends Thread
    private NetworkDispatcher[] mDispatchers;
    //该队列的所有缓存调度器 线程 开启后一直循环调度 extends Thread
    private CacheDispatcher mCacheDispatcher;
    

    上边是RequestQueue中所有的全局变量,由这些变量能看出什么吗?RequestQueue添加网络请求可以执行的本质其实是:创建RequestQueue实例,调用start()方法后,a.创建了一个缓存调度器(也就是线程),用来执行已执行且可缓存的网络请求; b.创建了多个网络调度器(也就是线程),用来执行未执行、或者缓存已过期等需要请求服务器的网络请求

    public void start() { 
      this.stop(); 
      // 保证所有正在运行的Dispatcher(也就是线程)都停止 
      // 创建缓存的派发器(也是一个线程),并启动线程。       
      this.mCacheDispatcher = new CacheDispatcher(this.mCacheQueue, this.mNetworkQueue, this.mCache, this.mDelivery); 
      this.mCacheDispatcher.start(); 
      for(int i = 0; i < this.mDispatchers.length; ++i) { 
        NetworkDispatcher networkDispatcher = new NetworkDispatcher(this.mNetworkQueue, this.mNetwork, this.mCache, this.mDelivery);
        this.mDispatchers[i] = networkDispatcher; 
        networkDispatcher.start(); 
      }
    }
    

    下边来看下NetworkDispatcher,让我们开看看网络调度器是怎么具体执行网络请求的。一般情况下,使用Volley框架,我们会在应用初始化的时候实例RequestQueue并启动,同时启动多个网络调度线程。

    public void run() { 
      Process.setThreadPriority(10); 
      while(true) { 
        long startTimeMs; 
        Request request; 
        while(true) { 
          startTimeMs = SystemClock.elapsedRealtime(); 
          try { //请求队列具有阻塞功能 
            request = (Request)this.mQueue.take(); 
            break; 
          } catch (InterruptedException var6) { 
            if(this.mQuit) { 
              return; 
            } 
          } 
        } try { 
          request.addMarker("network-queue-take"); 
          if(request.isCanceled()) { 
            request.finish("network-discard-cancelled"); 
          } else { 
            this.addTrafficStatsTag(request); 
            NetworkResponse e = this.mNetwork.performRequest(request); //最终的结果获得 
            BasicNetwork.performRequest(); 
            request.addMarker("network-http-complete"); 
            if(e.notModified && request.hasHadResponseDelivered()) { 
              //已有请求结果,并且有效 
              request.finish("not-modified"); 
            } else { 
              Response volleyError1 = request.parseNetworkResponse(e); 
              //解析响应结果 eg:JsonObjectRequest.parseNetworkResponse 解析为Json 
              request.addMarker("network-parse-complete"); 
              if(request.shouldCache() && volleyError1.cacheEntry != null) { 
                //缓存结果 
                this.mCache.put(request.getCacheKey(), volleyError1.cacheEntry); 
                request.addMarker("network-cache-written"); 
              } 
              request.markDelivered(); 
             //result->hasHadResponseDelivered()==true  
              this.mDelivery.postResponse(request, volleyError1); 
            } 
          } 
        } catch (VolleyError var7) { 
          var7.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs); 
          this.parseAndDeliverNetworkError(request, var7); 
        } catch (Exception var8) { 
          VolleyLog.e(var8, "Unhandled exception %s", new Object[]{var8.toString()}); 
          VolleyError volleyError = new VolleyError(var8); 
          volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
          this.mDelivery.postError(request, volleyError); 
        } 
      }
    }
    

    BasicNetwork.performRequest(request)又是怎么获取结果的呢?

    public NetworkResponse performRequest(Request<?> request) throws VolleyError { 
      long requestStart = SystemClock.elapsedRealtime(); 
      while(true) { 
        HttpResponse httpResponse = null; 
        Object responseContents = null; 
        Map responseHeaders = Collections.emptyMap(); 
        try { 
          HashMap e = new HashMap(); 
          this.addCacheHeaders(e, request.getCacheEntry()); 
          httpResponse = this.mHttpStack.performRequest(request, e);     
          //Boss来了,It's here; 
          StatusLine statusCode1 = httpResponse.getStatusLine(); 
          int networkResponse1 = statusCode1.getStatusCode(); 
          ...
        }
      }
    }
    

    具体的就不在这里说明了。那么如果想用Volley的上层,OkHttp的底层,又怎么来实现呢?最终请求是通过调用HttpStack.performRequest()得到响应结果的,这个HttpStack是在实例RequestQueue时赋值的。再回头看下之前的代码。

    public static RequestQueue newRequestQueue(Context context, HttpStack stack) { 
      ... 
      if(stack == null) { 
        if(VERSION.SDK_INT >= 9) { 
          stack = new HurlStack(); 
        } else { 
          stack = new HttpClientStack(AndroidHttpClient.newInstance(userAgent)); 
        } 
      } 
      ...
    }
    

    所以只需要继承HttpStack(如 OkHttp3Stack),重写performRequest() 方法,实例RequestQueue时使用 OkHttp3Stack即可。 详情之后继续分析。

    相关文章

      网友评论

          本文标题:Volley+OkHttp学习笔记

          本文链接:https://www.haomeiwen.com/subject/skwbjttx.html