Android Volley框架使用源码分享

过去在Android上网络通信都是使用的Xutils 因为用它可以顺道处理了图片和网络这两个方面,后来发觉Xutils里面使用的是HttpClient  而Google在6.0的版本上已经把HttpClient废除了,所以开始寻找新的网络框架,okhttp也用过,但是它是在作用在UI线程,使用起来还需要用handler 所以就先用着Volley框架了。  这里我先分析下Volley框架的简单网络请求的源码。

使用Volley请求网络数据的简单过程:

RequestQueue queue = Volley.newRequestQueue(this); //实例化一个请求队列 Google推荐写一个单例类 获取唯一一个队列
 StringRequest request = new StringRequest(Request.Method.POST, url1, new Response.Listener<String>() {
      @Override
      public void onResponse(String response) {
        Toast.makeText(MainActivity.this, "success"+response, Toast.LENGTH_SHORT).show();
      }
    }, new Response.ErrorListener() {
      @Override
      public void onErrorResponse(VolleyError error) {
        Toast.makeText(MainActivity.this, "失败了"+error.getMessage(), Toast.LENGTH_SHORT).show();
      }
    }){
      @Override
      protected Map<String, String> getParams() throws AuthFailureError { //重写这个函数提交参数 也可以重写一个Request实现这个方法
        Map<String,String> params = new HashMap<>();
        params.put(aaa+"name","1233555"); //参数
        return params;
      }
    };
    queue.add(request); 

请求的处理在newRequestQueue的时候就开始执行了  只不过那时候请求队列中还没有请求  所以阻塞了 当 add的方法执行时  才开始真正请求网络 
所以我们先来看  queue.add(request)  方法

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)) { //判断当前正在被处理并可以缓存的请求中是否包含该请求的key 如果包含说明已经有一个相同的请求 那么就加入到其中
      // 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;
  }
}

分析add方法  首先加入到mCurrentRequests集合中  这个集合存放所有这个队列所处理的请求  然后判断这个请求是否需要缓存,如果不需要缓存,那么直接加入mNetworkQueue队列中等待处理即可,如果需要那么最终加入到mCacheQueue队列中,因为RequestQueue在处理请求时总会先处理缓存的任务,在处理缓存时如果第一次处理没有缓存还是会加入mNetworkQueue队列中处理,如果有缓存那么就直接获取缓存了,之后判断当前的请求中是否有相同的请求,如果有的话那么就把这个请求加入到暂存集合中,如果没有那么就加入一个空的到请求到暂存队列中,用来以后判断是否有和这个请求相同的请求,然后加入缓存队列中即可。

然后我们来看RequstQueue的创建过程

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; //用户代理为app包名+版本号
    } catch (NameNotFoundException e) {
    } 

    if (stack == null) { //如果没传入HttpStack 那么采用下述默认的  这里可以自行重写扩展HttpStack 体现了该框架的高扩展性
      if (Build.VERSION.SDK_INT >= 9) { //如果sdk版本高于2.3 采用HurlStack 内部是httpUrlConnection实现
        stack = new HurlStack();
      } else { //如果版本低于2.3 采用httpClientStack
        // 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 = new RequestQueue(new DiskBasedCache(cacheDir), network); //实例化一个请求队列 传入参数
    queue.start(); 

    return queue;
  }
</pre><pre code_snippet_id="1680121" snippet_file_name="blog_20160512_5_2241745" name="code" class="java">public RequestQueue(Cache cache, Network network, int threadPoolSize) { //构造函数 会创建默认的ExecutorDelivery 用于回调
    this(cache, network, threadPoolSize,
        new ExecutorDelivery(new Handler(Looper.getMainLooper())));
  }

RequestQueue的创建过程也比较简单   根据sdk版本号判断使用HttpURLConnection还是HttpClient  因为在2.3之前 httpUrlConnection有一个重大的bug  所以使用HttpClient代替,而httpUrlConnection体积小  支持gzip压缩和缓存,并且速度相对httpClient快 并逐渐优化 所以选择httpUrlConnection   之后根据创建的NetWork 创建RequestQueue队列 然后开启即可 
之后我们查看  queue的start方法

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); //创建一个缓存调度器 是一个线程 start后执行run方法
    mCacheDispatcher.start(); 

    // Create network dispatchers (and corresponding threads) up to the pool size.
    for (int i = 0; i < mDispatchers.length; i++) { //默认会有4个NetworkDispatcher 为了提高效率 执行netWorkQueue里的request
      NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,
          mCache, mDelivery);
      mDispatchers[i] = networkDispatcher;
      networkDispatcher.start();
    }
  }

这个方法 先执行缓存调度器线程然后执行4个网络工作调度器线程,因为在缓存调度器中 会判断是否缓存过,如果缓存过并且没过期,就直接复用缓存的,不把任务加入netWordQueue中 所以下面的NetWork调度器线程就会取不到请求而阻塞,不会执行,而如果没有缓存,缓存调度器线程中就会把请求加入NetWork队列中,下面的netWork调度器就会取到该请求并执行了  
我们仔细看一下CacheDispatcher线程的源码:

run方法的代码比较长 我们分开来看  先看第一部分

@Override
 public void run() {
   if (DEBUG) VolleyLog.v("start new dispatcher");
   Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //设置线程的优先级  值为10 

   // 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"); //添加缓存miss标记
         // Cache miss; send off to the network dispatcher.
         mNetworkQueue.put(request); //换区缓存失败 添加到netWork中等待请求
         continue;
       } 

       // If it is completely expired, just send it to the network.
       if (entry.isExpired()) { //判断缓存是否过期了 如果过期了 那么就添加到netWork中等待请求
         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( //把读取到的缓存内容解析成Response对象
            new NetworkResponse(entry.data, entry.responseHeaders));
        request.addMarker("cache-hit-parsed"); //添加标记 

        if (!entry.refreshNeeded()) { //如果缓存不需要刷新 直接调用 mDelivery.postResponse方法  在其中会回调request的listener接口
          // Completely unexpired cache hit. Just deliver the response.
          mDelivery.postResponse(request, response);
        } else { //如果需要刷新  把请求加入mNetworkQueue中 等待请求
          // 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;
      }
    }
  }

上面代码的具体过程也很简单  首先从缓存请求队列取出一个请求,在缓存中看看有没有该请求的缓存,如果没有 那么 请求放入NetWork调度器中  等待调用  如果有 也分几种情况  如果获取到的是空,放入NetWOrk   如果过期 放入 NetWork  如果不需要刷新  就直接从缓存获取响应信息并解析  然后用mDelivery回调接口即可   如果需要刷新 放入NetWOrd队列等待调用。。。

我们再来看看NetworkDispatcher 线程的代码就可以了 类似于CacheDispatcher的代码:

@Override
  public void run() {
    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); //设置优先级 10
    while (true) {
      long startTimeMs = SystemClock.elapsedRealtime(); //获取请求执行开始时间
      Request<?> request;
      try {
        // Take a request from the queue.
        request = mQueue.take(); //从队列获取一个请求 没有则阻塞
      } catch (InterruptedException e) {
        // We may have been interrupted because it was time to quit.
        if (mQuit) {
          return;
        }
        continue;
      } 

      try {
        request.addMarker("network-queue-take"); 

        // If the request was cancelled already, do not perform the
        // network request.
        if (request.isCanceled()) {
          request.finish("network-discard-cancelled");
          continue;
        } 

        addTrafficStatsTag(request);  

        // Perform the network request.
        NetworkResponse networkResponse = mNetwork.performRequest(request); //真正执行请求的函数  并返回响应
        request.addMarker("network-http-complete"); 

        // If the server returned 304 AND we delivered a response already,
        // we're done -- don't deliver a second identical response.
        if (networkResponse.notModified && request.hasHadResponseDelivered()) {
          request.finish("not-modified");
          continue;
        } 

        // Parse the response here on the worker thread.
        Response<?> response = request.parseNetworkResponse(networkResponse); //解析响应
        request.addMarker("network-parse-complete"); 

        // Write to cache if applicable.
        // TODO: Only update cache metadata instead of entire record for 304s.
        if (request.shouldCache() && response.cacheEntry != null) { //如果需要缓存 那么把响应的信息存入缓存中
          mCache.put(request.getCacheKey(), response.cacheEntry);
          request.addMarker("network-cache-written");
        } 

        // Post the response back.
        request.markDelivered();
        mDelivery.postResponse(request, response); //之后回调一些方法
      } catch (VolleyError volleyError) {
        volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
        parseAndDeliverNetworkError(request, volleyError); //回调错误接口
      } catch (Exception e) {
        VolleyLog.e(e, "Unhandled exception %s", e.toString());
        VolleyError volleyError = new VolleyError(e);
        volleyError.setNetworkTimeMs(SystemClock.elapsedRealtime() - startTimeMs);
        mDelivery.postError(request, volleyError);  //回调错误接口
      }
    }
  }

NetworkDispatcher 线程的执行过程  先从 networkDispatch中获取一个请求  然后判断 是否取消了  如果没有 那么就执行NetWOrk的performRequest方法  执行http请求,这个函数内部才是真正的请求数据  ,请求后 根据设置的shouldCache标志 判断是否放入缓存中  之后回调一些接口方法 即可  这样就完成了一个请求

最后我们看一看NetWork类mNetwork.performRequest(request)方法是如何提交请求的吧   代码比较长 但是不难:

@Override
  public NetworkResponse performRequest(Request<?> request) throws VolleyError {
    long requestStart = SystemClock.elapsedRealtime(); //记录开始时间
    while (true) {
      HttpResponse httpResponse = null;
      byte[] responseContents = null;
      Map<String, String> responseHeaders = Collections.emptyMap(); //初始化响应头为空
      try {
        // Gather headers.
        Map<String, String> headers = new HashMap<String, String>(); //请求头
        addCacheHeaders(headers, request.getCacheEntry()); //根据缓存添加请求头
        httpResponse = mHttpStack.performRequest(request, headers); //调用HttpStack的方法请求网络
        StatusLine statusLine = httpResponse.getStatusLine();
        int statusCode = statusLine.getStatusCode(); 

        responseHeaders = convertHeaders(httpResponse.getAllHeaders()); //获取响应头
        // Handle cache validation.
        if (statusCode == HttpStatus.SC_NOT_MODIFIED) {  //如果为304 读取的缓存  

          Entry entry = request.getCacheEntry(); //查看以前是否缓存过
          if (entry == null) { //如果以前缓存的为空 那么 说明上次缓存的请求也为空 直接返回response
            return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, null,
                responseHeaders, true,
                SystemClock.elapsedRealtime() - requestStart);
          } 

          // A HTTP 304 response does not have all header fields. We
          // have to use the header fields from the cache entry plus
          // the new ones from the response.
          // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5
          entry.responseHeaders.putAll(responseHeaders); //如果不空 那么就添加头 然后返回 数据了
          return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED, entry.data,
              entry.responseHeaders, true,
              SystemClock.elapsedRealtime() - requestStart);
        } 

        // Some responses such as 204s do not have content. We must check.
        if (httpResponse.getEntity() != null) { //不是304的情况
     responseContents = entityToBytes(httpResponse.getEntity()); //获取响应的内容 下面返回响应即可
    } else {
     // Add 0 byte response as a way of honestly representing a
     // no-content request.
     responseContents = new byte[0];
    } 

    // if the request is slow, log it.
    long requestLifetime = SystemClock.elapsedRealtime() - requestStart;
    logSlowRequests(requestLifetime, request, responseContents, statusLine); 

    if (statusCode < 200 || statusCode > 299) {
      throw new IOException();
    }
    return new NetworkResponse(statusCode, responseContents, responseHeaders, false,
        SystemClock.elapsedRealtime() - requestStart);
  } catch (SocketTimeoutException e) {
    attemptRetryOnException("socket", request, new TimeoutError());
  } catch (ConnectTimeoutException e) {
    attemptRetryOnException("connection", request, new TimeoutError());
  } catch (MalformedURLException e) {
    throw new RuntimeException("Bad URL " + request.getUrl(), e);
  } catch (IOException e) {
    int statusCode = 0;
    NetworkResponse networkResponse = null;
    if (httpResponse != null) {
      statusCode = httpResponse.getStatusLine().getStatusCode();
    } else {
      throw new NoConnectionError(e);
    }
    VolleyLog.e("Unexpected response code %d for %s", statusCode, request.getUrl());
    if (responseContents != null) {
      networkResponse = new NetworkResponse(statusCode, responseContents,
          responseHeaders, false, SystemClock.elapsedRealtime() - requestStart);
      if (statusCode == HttpStatus.SC_UNAUTHORIZED ||
          statusCode == HttpStatus.SC_FORBIDDEN) {
        attemptRetryOnException("auth",
            request, new AuthFailureError(networkResponse));
      } else {
        // TODO: Only throw ServerError for 5xx status codes.
        throw new ServerError(networkResponse);
      }
    } else {
      throw new NetworkError(networkResponse);
    }
  }
} 

然后看 HttpStack的 请求代码:

@Override
  public HttpResponse performRequest(Request<?> request, Map<String, String> additionalHeaders)
      throws IOException, AuthFailureError {
    String url = request.getUrl();
    HashMap<String, String> map = new HashMap<String, String>();
    map.putAll(request.getHeaders()); //添加请求头
    map.putAll(additionalHeaders);
    if (mUrlRewriter != null) {
      String rewritten = mUrlRewriter.rewriteUrl(url);
      if (rewritten == null) {
        throw new IOException("URL blocked by rewriter: " + url);
      }
      url = rewritten;
    }
    URL parsedUrl = new URL(url);
    HttpURLConnection connection = openConnection(parsedUrl, request); //打开连接
    for (String headerName : map.keySet()) { //设置头
      connection.addRequestProperty(headerName, map.get(headerName));
    }
    setConnectionParametersForRequest(connection, request); //在这个函数里添加请求的参数 和一些基本的信息配置
    // Initialize HttpResponse with data from the HttpURLConnection.
    ProtocolVersion protocolVersion = new ProtocolVersion("HTTP", 1, 1);
    int responseCode = connection.getResponseCode(); //下面就是些获取响应信息后的处理了
    if (responseCode == -1) {
      // -1 is returned by getResponseCode() if the response code could not be retrieved.
      // Signal to the caller that something was wrong with the connection.
      throw new IOException("Could not retrieve response code from HttpUrlConnection.");
    }
    StatusLine responseStatus = new BasicStatusLine(protocolVersion,
        connection.getResponseCode(), connection.getResponseMessage());
    BasicHttpResponse response = new BasicHttpResponse(responseStatus);
    response.setEntity(entityFromConnection(connection));
    for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
      if (header.getKey() != null) {
        Header h = new BasicHeader(header.getKey(), header.getValue().get(0));
        response.addHeader(h);
      }
    }
    return response;
  }

这个函数中主要是HttpUrlConnection的使用 添加头在 connection.addRequestProperty方法中  添加参数需要获取流 然后写入参数  下面这个函数中有介绍 假设是post方式:

case Method.POST:
        connection.setRequestMethod("POST");
        addBodyIfExists(connection, request);
        break;
private static void addBodyIfExists(HttpURLConnection connection, Request<?> request)
      throws IOException, AuthFailureError {
    byte[] body = request.getBody();
    if (body != null) {
      connection.setDoOutput(true);
      connection.addRequestProperty(HEADER_CONTENT_TYPE, request.getBodyContentType());
      DataOutputStream out = new DataOutputStream(connection.getOutputStream());
      out.write(body);
      out.close();
    }
  }

将body写入到流中 就可以  参数的封装在 body中

public byte[] getBody() throws AuthFailureError {
    Map<String, String> params = getParams();
    if (params != null && params.size() > 0) {
      return encodeParameters(params, getParamsEncoding());
    }
    return null;
  }
getParams方法 是Request需要重写的一个方法 返回值就是参数的Map集合
[java] view plain copy 在CODE上查看代码片派生到我的代码片
private byte[] encodeParameters(Map<String, String> params, String paramsEncoding) {
    StringBuilder encodedParams = new StringBuilder();
    try {
      for (Map.Entry<String, String> entry : params.entrySet()) {
        encodedParams.append(URLEncoder.encode(entry.getKey(), paramsEncoding));
        encodedParams.append('=');
        encodedParams.append(URLEncoder.encode(entry.getValue(), paramsEncoding));
        encodedParams.append('&');
      }
      return encodedParams.toString().getBytes(paramsEncoding);
    } catch (UnsupportedEncodingException uee) {
      throw new RuntimeException("Encoding not supported: " + paramsEncoding, uee);
    }
  }

这个函数就是按照一定规则拼接字符串参数即可  然后 就可以提交参数了

最后介绍下这个框架主要的几个类、成员及他们作用:

RequestQueue    用来处理请求的队列,请求都放在这个类中  调用start方法 开始处理请求

mCache   请求的缓存,当提交了一个请求 并且此请求需要缓存时,会放入这个缓存中

mNetwork  单纯用于提交网络请求的接口  只有一个提交请求的方法  需要传入一个HttpStack来完成请求的提交

mDelivery  用于请求响应后的 接口回调等功能

mDispatchers  NetWork调度器线程数组  包含4个对象处理请求  目的是为了提高效率   当没有缓存可以获取或者已经过期  需要刷新时  会调用这个线程的run方法  如果没有 则阻塞

mCacheDispatcher  缓存调度器线程   处理已经缓存了的请求   如果没有缓存 则将请求放入 NetWorkQueue 等待调用

以上就是本文的全部内容,希望对大家学习Android Volley框架有所帮助。

(0)

相关推荐

  • Android的HTTP操作库Volley的基本使用教程

    以前原本都用android内建的Library来进行GET.POST等等对API的连线与操作. 但最近想说来找找看有没有好用的library,应该可以事半功倍. 当初有找了三套比较多人用的 1.Android Asynchronous Http Client 2.okhttp square开发并且开源的,因为之前用过他们家的picasso,所以对这套满有好感的,只可惜使用方式不太喜欢 3.Volley Volley是Google在2013年Google I/O的时候发布的,到现在已经积累了很高的

  • Android的HTTP类库Volley入门学习教程

    1. 什么是Volley 我们平时在开发Android应用的时候不可避免地都需要用到网络技术,而多数情况下应用程序都会使用HTTP协议来发送和接收网络数据.Android系统中主要提供了两种方式来进行HTTP通信,HttpURLConnection和HttpClient,几乎在任何项目的代码中我们都能看到这两个类的身影,使用率非常高. 不过HttpURLConnection和HttpClient的用法还是稍微有些复杂的,如果不进行适当封装的话,很容易就会写出不少重复代码.于是乎,一些Androi

  • 从源码分析Android的Volley库的工作流程

    Volley现在已经被官方放到AOSP里面,已经逐步成为Android官方推荐的网络框架. 类抽象 对Http协议的抽象 Requeset 顾名思义,对请求的封装,实现了Comparable接口,因为在Volley中是可以指定请求的优先级的,实现Comparable是为了在Request任务队列中进行排序,优先级高的Request会被优先调度执行. NetworkResponse Http响应的封装,其中包括返回的状态码 头部 数据等. Response 给调用者返回的结果封装,它比Networ

  • Android 网络请求框架Volley实例详解

    Android 网络请求框架Volley实例详解 首先上效果图 Logcat日志信息on Reponse Volley特别适合数据量不大但是通信频繁的场景,像文件上传下载不适合! 首先第一步 用到的RequetQueue RequestQueue.Java RequestQueue请求队列首先得先说一下,ReuqestQueue是如何对请求进行管理的...RequestQueue是对所有的请求进行保存...然后通过自身的start()方法开启一个CacheDispatcher线程用于缓存调度,开

  • Android Volley框架全面解析

     Volley简介 我们平时在开发Android应用的时候不可避免地都需要用到网络技术,而多数情况下应用程序都会使用HTTP协议来发送和接收网络数据.Android系统中主要提供了两种方式来进行HTTP通信,HttpURLConnection和HttpClient,几乎在任何项目的代码中我们都能看到这两个类的身影,使用率非常高. 不过HttpURLConnection和HttpClient的用法还是稍微有些复杂的,如果不进行适当封装的话,很容易就会写出不少重复代码.于是乎,一些Android网络

  • 深入剖析Android的Volley库中的图片加载功能

    一.基本使用要点回顾 Volley框架在请求网络图片方面也做了很多工作,提供了好几种方法.本文介绍使用ImageLoader来进行网络图片的加载. ImageLoader的内部使用ImageRequest来实现,它的构造器可以传入一个ImageCache缓存形参,实现了图片缓存的功能,同时还可以过滤重复链接,避免重复发送请求. 下面是ImageLoader加载图片的实现方法: public void displayImg(View view){ ImageView imageView = (Im

  • Android开发中使用Volley库发送HTTP请求的实例教程

    Android Volley 是Google开发的一个网络lib,可以让你更加简单并且快速的访问网络数据.Volley库的网络请求都是异步的,你不必担心异步处理问题. Volley的优点: 请求队列和请求优先级 请求Cache和内存管理 扩展性性强 可以取消请求 下载和编译volley.jar 需要安装git,ant,android sdk clone代码: git clone https://android.googlesource.com/platform/frameworks/volley

  • Android 开发中Volley详解及实例

    Android 开发中Volley详解及实例 最近在做项目的时候,各种get和post.简直要疯了,我这种啥都不了解的,不知道咋办了,然后百度看了下,可以用volley进行网络请求与获取,下面就介绍下volley的用法. volley有三种方式:JsonObjectRequest,JsonArrayRequest,StringRequest.其实都是差不多了,举一反三就ok了,这里我就讲下JsonObjectRequest. 方法如下: JsonObjectRequest jsonObjectR

  • Android Volley框架使用源码分享

    过去在Android上网络通信都是使用的Xutils 因为用它可以顺道处理了图片和网络这两个方面,后来发觉Xutils里面使用的是HttpClient  而Google在6.0的版本上已经把HttpClient废除了,所以开始寻找新的网络框架,okhttp也用过,但是它是在作用在UI线程,使用起来还需要用handler 所以就先用着Volley框架了.  这里我先分析下Volley框架的简单网络请求的源码. 使用Volley请求网络数据的简单过程: RequestQueue queue = Vo

  • 实时获取股票数据的android app应用程序源码分享

    最近学习Android应用开发,不知道写一个什么样的程序来练练手,正好最近股票很火,就一个App来实时获取股票数据,取名为Mystock.使用开发工具Android Studio,需要从Android官网下载,下载地址:http://developer.android.com/sdk/index.html.不幸的是Android是Google公司的,任何和Google公司相关的在国内都无法直接访问,只能通过VPN访问. 下图为Android Studio打开一个工程的截图: 下面按步介绍Myst

  • ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统之前端页面框架构建源码分享

    开始,我们有了一系列的解决方案,我们将动手搭建新系统吧. 用户的体验已经需要越来越注重,这次我们是左右分栏,左边是系统菜单,右边是一个以tabs页组成的页面集合,每一个tab都可以单独刷新和关闭,因为他们会是一个iframe 工欲善其事必先利其器.需要用到以下工具. Visual Studio 2012 您可以安装MVC4 for vs2010用VS2010来开发,但是貌似你将不能使用EF5.0将会是EF4.4版本,但这没有多大的关系. MVC4将挂载在.NET Framework4.5上. 好

  • Android 用Time和Calendar获取系统当前时间源码分享(年月日时分秒周几)

    概述 用Time和Calendar获取系统当前时间(年月日时分秒周几) 效果图 源码: import android.app.Activity; import android.os.Bundle; import android.text.format.Time; import android.view.View; import android.widget.RelativeLayout; import android.widget.TextView; import java.util.Calen

  • 非常实用的js验证框架实现源码 附原理方法

    本文为大家分享一个很实用的js验证框架实现源码,供大家参考,具体内容如下 关键方法和原理: function check(thisInput) 方法中的 if (!eval(scriptCode)) { return false; } 调用示例: 复制代码 代码如下: <input type="text" class="text_field percentCheck" name="progress_payment_two" id="

  • 最新热门脚本Autojs源码分享

    今天给大家分享一个包含最新50个热门脚本合集的源码,目前包括:矿牛守卫赚.热血星际.捉妖特工队.体重保卫战.炎兔.魔兽红包群.横扫太空.疯狂合体鸭.动物星球.猜猜什么歌等最热门的脚本源码,源码可以直接运行.学完直接可以开撸代码,成为大神. 需要源码的可以从此处下载哦,非常不错的autojs源码. http://xiazai.jb51.net/202105/yuanma/autojsym_jb51.rar 部分源码截图: 部分源码截取: function 判断() { while (true) {

  • Java编程删除链表中重复的节点问题解决思路及源码分享

    一. 题目 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. 二. 例子 输入链表:1->2->3->3->4->4->5 处理后为:1->2->5 三. 思路 个人感觉这题关键是注意指针的指向,可以定义一个first对象(值为-1,主要用于返回操作后的链表),first.next指向head,定义一个last同样指向first(主要用于操作记录要删除节点的前一个节点),定义一个p指向head,指向当前节点.

  • WPF实现类似360安全卫士界面的程序源码分享

    下面通过图文并茂的方式给大家介绍WPF实现类似360安全卫士界面的程序源码分享,点击此处下载源码哦. 以前学习Windows Form编程的时候,总感觉自己做的界面很丑,看到360安全卫士.迅雷等软件的UI设计都非常美观,心里总是憧憬着要是自己能实现这样的UI效果该多好!!!另一个困扰我的问题是,这个UI皮肤是如何用技术实现的呢?!虽然好多年过去了,但心里的憧憬和疑惑一直没有消失,而且越来越强烈.在日常的工作和学习中,自己在网上也经常留意类似的技术或者文章.最近在学习WPF的过程中,看到网上也有

  • jQuery复制表单元素附源码分享效果演示

    我们在提交表单时,有时会遇到需要重复添加多个相同表单元素,如订单信息中需要添加多个不同型号的产品.表单数据中新增字段信息等.这个时候我们可以在表单中直接放置一个"新增一项"或"复制"按钮,通过点击按钮即可实现复制表单元素. 查看演示 下载源码 HTML 本文我们通过实例介绍一款简单的基于jQuery的元素复制插件,通过调用该插件轻松实现元素复制功能. 首先载入jQuery库文件和元素复制插件duplicateElement.min.js. <script sr

  • Android消息循环机制源码深入理解

    Android消息循环机制源码 前言: 搞Android的不懂Handler消息循环机制,都不好意思说自己是Android工程师.面试的时候一般也都会问这个知识点,但是我相信大多数码农肯定是没有看过相关源码的,顶多也就是网上搜搜,看看别人的文章介绍.学姐不想把那个万能的关系图拿出来讨论. 近来找了一些关于android线程间通信的资料,整理学习了一下,并制作了一个简单的例子. andriod提供了 Handler 和 Looper 来满足线程间的通信.例如一个子线程从网络上下载了一副图片,当它下

随机推荐