Volley简单学习使用五—— 源代码分析三

一、Volley工作流程图:


二、Network
    在NetworkDispatcher中须要处理的网络请求。由以下进行处理:
    NetworkResponse networkResponse = mNetwork.performRequest(request);
看一下mNetwork的定义:(定义在NetworkDispatcher中)

    /** The network interface for processing requests. */private final Network mNetwork;
NetworkDispatcher.mNetwork初始化发生在RequestQueue.start()中:

    NetworkDispatcher networkDispatcher = new NetworkDispatcher(mNetworkQueue, mNetwork,mCache, mDelivery);
而RequestQueue.mNetwork是在其构造函数中传入的:

    public RequestQueue(Cache cache, Network network, int threadPoolSize,ResponseDelivery delivery) {mCache = cache;mNetwork = network;mDispatchers = new NetworkDispatcher[threadPoolSize];mDelivery = delivery;}
由前面分析知RequestQueue的构建是在Volley.newRequestQueue中实现的:

    //创建以stack为參数的Network对象Network network = new BasicNetwork(stack);//创建RequestQueue对象RequestQueue queue = new RequestQueue(new DiskBasedCache(cacheDir), network);queue.start();//继续向下分析的入口

    能够看出mNetwork事实上是BasicNetwork对象。
    则NetworkResponse中mNetwork实际上调用的是BasicNetwork.performRequest(),这是一个专门用来处理网络请求的函数,其作用为调用HttpStack处理请求,并将结果转换为可被ResponseDelivery处理的NetworkResponse
看一下其源代码:
   @Overridepublic NetworkResponse performRequest(Request<?> request) throws VolleyError {long requestStart = SystemClock.elapsedRealtime();while (true) {HttpResponse httpResponse = null;byte[] responseContents = null;Map<String, String> responseHeaders = new HashMap<String, String>();try {/** 忽略网络处理的细节*/// Gather headers.Map<String, String> headers = new HashMap<String, String>();addCacheHeaders(headers, request.getCacheEntry());/**运行网络请求* 这里调用了HttpStack.performRequest。并得到一个HttpResponse返回结果*/httpResponse = mHttpStack.performRequest(request, headers);StatusLine statusLine = httpResponse.getStatusLine();int statusCode = statusLine.getStatusCode();responseHeaders = convertHeaders(httpResponse.getAllHeaders());/**新奇度验证:* 304 Not Modified:client有缓冲的文件并发出了一个条件性的请求* (通常是提供If-Modified-Since头表示客户仅仅想比指定日期更新的文档)。* server告诉客户。原来缓冲的文档还能够继续使用。*/if (statusCode == HttpStatus.SC_NOT_MODIFIED) {/** 解析成NetworkResponse,返回*/return new NetworkResponse(HttpStatus.SC_NOT_MODIFIED,request.getCacheEntry().data, responseHeaders, true);}// 推断responses是否有实体信息,一些响应如204,并不包括content。所以须要验证if (httpResponse.getEntity() != null) {//实体信息转化成byte[]responseContents = entityToBytes(httpResponse.getEntity());} else {// 无实体信息情况responseContents = new byte[0];}// 超时情况处理.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);} 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) {...}}}

 总结一下Network.performRequest所做的工作:

1、由传入的HttpStack对象运行网络请求:mHttpStack.performRequest()

2、解析响应结果,将HttpResponse解析成NetworkResponse;

3、对返回结果进行新奇度验证(304)

4、将response的实体信息转化为byte数组

5、超时情况处理,假设发生超时,认证失败等错误。进行重试操作(attemptRetryOnException)。直到成功、抛出异常(不满足重试策略等)结束。


attemptRetryOnException()是依据重试策略进行请求重试操作:

    /*** Attempts to prepare the request for a retry. If there are no more attempts remaining in the* request's retry policy, a timeout exception is thrown.*/private static void attemptRetryOnException(String logPrefix, Request<?

> request, VolleyError exception) throws VolleyError { RetryPolicy retryPolicy = request.getRetryPolicy(); int oldTimeout = request.getTimeoutMs(); try { retryPolicy.retry(exception); } catch (VolleyError e) { request.addMarker( String.format("%s-timeout-giveup [timeout=%s]", logPrefix, oldTimeout)); throw e; } request.addMarker(String.format("%s-retry [timeout=%s]", logPrefix, oldTimeout)); }

三、HttpClientStack、HurlStack
    据上面源代码知。网络请求处理的逻辑实际上是交由传进来的參数HttpStack进行处理。

前面已经分析过。Android2.3之前使用 HttpClientStack,之后使用HurlStack。

1、先看两者的父类HttpStack:
    public interface HttpStack {/*** Performs an HTTP request with the given parameters.* <p>A GET request is sent if request.getPostBody() == null. A POST request is sent otherwise,* and the Content-Type header is set to request.getPostBodyContentType().</p>* @param request the request to perform* @param 发起请求之前,加入额外的请求 Headers {@link Request#getHeaders()}*/public HttpResponse performRequest(Request<?

> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError; }

2、HttpClientStack(使用HttpClient来实现)

    @Overridepublic HttpResponse performRequest(Request<?

> request, Map<String, String> additionalHeaders) throws IOException, AuthFailureError { HttpUriRequest httpRequest = createHttpRequest(request, additionalHeaders);//见附一 addHeaders(httpRequest, additionalHeaders); addHeaders(httpRequest, request.getHeaders()); onPrepareRequest(httpRequest);// Nothing.空函数,用于重写;该函数在request被excute之前被调用 //一些网络设置 HttpParams httpParams = httpRequest.getParams(); int timeoutMs = request.getTimeoutMs(); // TODO: Reevaluate this connection timeout based on more wide-scale // data collection and possibly different for wifi vs. 3G. HttpConnectionParams.setConnectionTimeout(httpParams, 5000); HttpConnectionParams.setSoTimeout(httpParams, timeoutMs); return mClient.execute(httpRequest); }

附一:createHttpRequest函数:

    /*** 依据传进来的request来构造合适的HttpUriRequest*/static HttpUriRequest createHttpRequest(Request<?> request,Map<String, String> additionalHeaders) throws AuthFailureError {switch (request.getMethod()) {case Method.DEPRECATED_GET_OR_POST: {// This is the deprecated way that needs to be handled for backwards compatibility.// If the request's post body is null, then the assumption is that the request is// GET.  Otherwise, it is assumed that the request is a POST.byte[] postBody = request.getPostBody();if (postBody != null) {HttpPost postRequest = new HttpPost(request.getUrl());postRequest.addHeader(HEADER_CONTENT_TYPE, request.getPostBodyContentType());HttpEntity entity;entity = new ByteArrayEntity(postBody);postRequest.setEntity(entity);return postRequest;} else {return new HttpGet(request.getUrl());}}/***********一般较多使用的是POST与GET。其等同于HttpClient的一般使用流程***************/case Method.GET:return new HttpGet(request.getUrl());case Method.DELETE:return new HttpDelete(request.getUrl());case Method.POST: {HttpPost postRequest = new HttpPost(request.getUrl());//这里就看到了前面实现Request时,重写getBodyContentType()函数的意义postRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());setEntityIfNonEmptyBody(postRequest, request);return postRequest;}case Method.PUT: {HttpPut putRequest = new HttpPut(request.getUrl());putRequest.addHeader(HEADER_CONTENT_TYPE, request.getBodyContentType());setEntityIfNonEmptyBody(putRequest, request);return putRequest;}default:throw new IllegalStateException("Unknown request method.");}}
3、HurlStack(由HttpURLConnection来实现)
    @Overridepublic 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);//UrlRewriter见附一if (mUrlRewriter != null) {String rewritten = mUrlRewriter.rewriteUrl(url);if (rewritten == null) {thrownew IOException("URL blocked by rewriter: " + url);}url = rewritten;}/**************HttpURLConnection的一般使用流程*******************/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.thrownew 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;}
附一:UrlRewriter

    /** 对URLs在使用前进行重写转换*/public interface UrlRewriter {/*** Returns a URL to use instead of the provided one, or null to indicate* this URL should not be used at all.*/public String rewriteUrl(String originalUrl);}
參数mUrlRewriter通过HttpStack的构造函数传入进来,故能够自行进行定义:
    public HurlStack(UrlRewriter urlRewriter, SSLSocketFactory sslSocketFactory) {mUrlRewriter = urlRewriter;mSslSocketFactory = sslSocketFactory;}

四、NetworkResponse
    回到起点NetworkDispatcher(Thread)中的run()函数,当中:

    NetworkResponse networkResponse = mNetwork.performRequest(request);

以下继续看NetworkResponse的源代码:
NetworkResponse类非常easy,仅是用以在多个类中传递数据,其成员变量:
1)成员变量
int statusCode Http 响应状态码

byte[] data Body 数据
Map<String, String> headers 响应 Headers
boolean notModified 表示是否为 304 响应
long networkTimeMs 请求耗时

2)其主体仅仅为几个构造函数:
    public NetworkResponse(int statusCode, byte[] data, Map<String, String> headers,boolean notModified) {this.statusCode = statusCode;this.data = data;this.headers = headers;this.notModified = notModified;}public NetworkResponse(byte[] data) {this(HttpStatus.SC_OK, data, Collections.<String, String>emptyMap(), false);}public NetworkResponse(byte[] data, Map<String, String> headers) {this(HttpStatus.SC_OK, data, headers, false);}
3)回想一下前面分析的设计NetworkResponse的类之间数据的传递关系:



这里的主体是依据NetworkDispatcher.run()函数进行分析的
0、函数中调用Network.performRequest();
     NetworkResponse networkResponse = mNetwork.performRequest(request);
     而Network.performRequest()是基于HttpStack实现的;
1、HttpClientStack与HurlStack(分别基于HttpClient与HttpURLConnection实现)中的public HttpResponse performRequest()函数返回HttpResponse ;
2、Network(实际为BasicNetwork)中performRequest()方法。使用1中的两个HttpStack类。获取到其返回值HttpResponse,然后将其解析成为NetworkResponse;
3、Request中 abstract protected Response<T> parseNetworkResponse(NetworkResponse response);
    将NetworkResponse解析成Response;
    而该函数的调用是在NetworkDispatcher中的run()函数中调用的。                
4、在NetworkDispatcher.run()的最后一步:
    mDelivery.postResponse(request, response);
    将response传递给了ResponseDelivery
后面继续看Delivery的逻辑;
ResponseDelivery mDelivery的实际类型是ExecutorDelivery:
public RequestQueue(Cache cache, Network network, int threadPoolSize) {this(cache, network, threadPoolSize,new ExecutorDelivery(new Handler(Looper.getMainLooper())));
}
public ExecutorDelivery(final Handler handler) {// Make an Executor that just wraps the handler.mResponsePoster = new Executor() {@Overridepublic void execute(Runnable command) {handler.post(command);}};}
能够看到非常easy,就是使用主线程的Looper构建一个Handler。以下全部的post操作都是调用这个Handler来运行Runnable;

比方:

@Override
public void postResponse(Request<?> request, Response<?> response, Runnable runnable) {request.markDelivered();request.addMarker("post-response");mResponsePoster.execute(new ResponseDeliveryRunnable(request, response, runnable));
}
将传递来的Response转化为ResponseDeliveryRunnable ,显然这是一个Runnable;

private class ResponseDeliveryRunnable implements Runnable {private final Request mRequest;private final Response mResponse;private final Runnable mRunnable;public ResponseDeliveryRunnable(Request request, Response response, Runnable runnable) {mRequest = request;mResponse = response;mRunnable = runnable;}@SuppressWarnings("unchecked")@Overridepublic void run() {// If this request has canceled, finish it and don't deliver.if (mRequest.isCanceled()) {mRequest.finish("canceled-at-delivery");return;}// Deliver a normal response or error, depending.if (mResponse.isSuccess()) {mRequest.deliverResponse(mResponse.result);} else {mRequest.deliverError(mResponse.error);}// If this is an intermediate response, add a marker, otherwise we're done// and the request can be finished.if (mResponse.intermediate) {mRequest.addMarker("intermediate-response");} else {mRequest.finish("done");}// If we have been provided a post-delivery runnable, run it.if (mRunnable != null) {mRunnable.run();}}}
在这个子线程中,转而调用 Request来deliverResponse:

以StringRequest为例,来看这个函数:

@Override
protected void deliverResponse(String response) {if (mListener != null) {mListener.onResponse(response);}
}
这个Listener就是自己在定义Request的时候声明的ResponseListener,能够看到这个Listener工作在子线程中,所以假设要更新界面,注意使用Handler把消息传递主线程进行处理。


***************************************************** Volley图片载入的实现 *******************************************************
Volley的图片载入主要还是基于上面的原理来实现的。详细例如以下:
ImageLoader的使用:
//创建ImageLoader
imageLoader = new ImageLoader(httpUtils.getRequestQueue(), imageCache);
public ImageLoader(RequestQueue queue, ImageCache imageCache) {mRequestQueue = queue;mCache = imageCache;}
这里面的ImageCache是自己定义的:
// 获取最大内存缓存大小
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
MAX_CACHE_SIZE = maxMemory / 8; // 定义为应用最大缓存的1/8mImageLruCache = new LruCache<String, Bitmap>(MAX_CACHE_SIZE){@Overrideprotected int sizeOf(String url, Bitmap bitmap){return bitmap.getRowBytes() * bitmap.getHeight() / 1024;}};// 创建ImageCache
imageCache = new ImageLoader.ImageCache() {@Overridepublic void putBitmap(String url, Bitmap bitmap) {mImageLruCache.put(url, bitmap);}@Overridepublic Bitmap getBitmap(String url) {return mImageLruCache.get(url);}
};
使用LruCache来实现ImageCache接口,实现图片的内存缓存:
public interface ImageCache {public Bitmap getBitmap(String url);public void putBitmap(String url, Bitmap bitmap);
}
载入图片时的使用方法:

imageListener = ImageLoader.getImageListener(myImageView, default_pg, failed_pg);
imageLoader.get(imageUrl, imageListener);
来到ImageLoader#get:

public ImageContainer get(String requestUrl, final ImageListener listener) {return get(requestUrl, listener, 0, 0);}public ImageContainer get(String requestUrl, ImageListener imageListener,int maxWidth, int maxHeight) {return get(requestUrl, imageListener, maxWidth, maxHeight, ImageView.ScaleType.CENTER_INSIDE);}public ImageContainer get(String requestUrl, ImageListener imageListener,int maxWidth, int maxHeight, ImageView.ScaleType scaleType) {// 假设操作不是在主线程,则直接抛出异常throwIfNotOnMainThread();// 为图片的URL创建一个特定的cacheKey,注意这个cache还和图片的大小及scaleType相关final String cacheKey = getCacheKey(requestUrl, maxWidth, maxHeight, scaleType);// 这里会使用自己定义的LruCache去获取一个Bitmap实例Bitmap cachedBitmap = mCache.getBitmap(cacheKey);// 假设缓存中已经存在。则直接返回if (cachedBitmap != null) {// Return the cached bitmap.ImageContainer container = new ImageContainer(cachedBitmap, requestUrl, null, null);imageListener.onResponse(container, true);return container;}// 假设缓存中不存在,则进行获取ImageContainer imageContainer =new ImageContainer(null, requestUrl, cacheKey, imageListener);// 通知Observer这时能够使用默认的图片imageListener.onResponse(imageContainer, true);// 推断是否已经有了一个同样的请求在等待BatchedImageRequest request = mInFlightRequests.get(cacheKey);if (request != null) {// If it is, add this request to the list of listeners.request.addContainer(imageContainer);return imageContainer;}// 创建一个Request,反复之前的流程Request<Bitmap> newRequest = makeImageRequest(requestUrl, maxWidth, maxHeight, scaleType,cacheKey);mRequestQueue.add(newRequest);mInFlightRequests.put(cacheKey,new BatchedImageRequest(newRequest, imageContainer));return imageContainer;
}
处理逻辑大致和前面的addRequest同样。首先推断缓存中是否已经存在该url相应的bitmap。假设存在直接返回;假设不存在,先推断是否已经有了一个同样的请求在等待。假设是,把这个请求加入到监听者链表中。假设不存在,则创建一个Request<Bitmap>,加入到RequestQueue中,从网络中去获取;从网络中获取的流程和前面分析的同样。


先来看Request<Bitmap>:

protected Request<Bitmap> makeImageRequest(String requestUrl, int maxWidth, int maxHeight,ScaleType scaleType, final String cacheKey) {return new ImageRequest(requestUrl, new Listener<Bitmap>() {@Overridepublic void onResponse(Bitmap response) {onGetImageSuccess(cacheKey, response);}}, maxWidth, maxHeight, scaleType, Config.RGB_565, new ErrorListener() {@Overridepublic void onErrorResponse(VolleyError error) {onGetImageError(cacheKey, error);}});
}
实际上返回一个ImageRequest类型。来看其请求成功的响应:即把获得的图片存储到缓存中。

protected void onGetImageSuccess(String cacheKey, Bitmap response) {// 把获取到的图片存储到缓存中mCache.putBitmap(cacheKey, response);// 能够看到假设是多个同样请求在等待,则能够同一时候进行更新处理BatchedImageRequest request = mInFlightRequests.remove(cacheKey);if (request != null) {// Update the response bitmap.request.mResponseBitmap = response;// Send the batched responsebatchResponse(cacheKey, request);}
}
最后NetWork运行的结果会封装成NetWorkResponse。通过ResponseDelivery进行转发,这个类最后会调用Request中deliverResponse方法:

@Override
protected void deliverResponse(Bitmap response) {mListener.onResponse(response);
}
这个Listener就是最初定义的ImageListener:

public static ImageListener getImageListener(final ImageView view,final int defaultImageResId, final int errorImageResId) {return new ImageListener() {@Overridepublic void onErrorResponse(VolleyError error) {if (errorImageResId != 0) {view.setImageResource(errorImageResId);}}@Overridepublic void onResponse(ImageContainer response, boolean isImmediate) {if (response.getBitmap() != null) {view.setImageBitmap(response.getBitmap());} else if (defaultImageResId != 0) {view.setImageResource(defaultImageResId);}}};
}

能够看到这里终于给View空间设置了图片,以上就是Volley实现图片载入的流程。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/258545.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

html5 - history 历史管理

参考文章&#xff1a; w3c : http://www.w3.org/html/ig/zh/wiki/HTML5/history 张鑫旭 : http://www.zhangxinxu.com/wordpress/2013/06/html5-history-api-pushstate-replacestate-ajax/ zawa : http://zawa.iteye.com/blog/1271031  Demo : Demo 截图&#xff…

Android开发学习---使用Intelij idea 13.1 进行android 开发

Android开发学习---使用Intelij idea 13.1 进行android 开发 原文:Android开发学习---使用Intelij idea 13.1 进行android 开发1.为什么放弃eclipse?太卡!! 实在受不了eclipse的卡了,运行WEB项目还好,但android开发实在太慢,太慢!经常卡死,CPU经常被占满! 看网上很多人都说比I…

Logcat打印调试信息

Android Logcat调试中的V、D、I、W、E的分别代表什么&#xff1f; Log.v -- 黑色 -- verbose infoLog.d -- 蓝色 -- debug infoLog.i -- 绿色 -- infoLog.w -- 橙色 -- warnLog.e -- 红色 -- error info//Log.ASSERT -- 断言 //Log.wtf() (1、Log.v 的调试颜色为黑色的&#xf…

C# .net core 使用自定义的WebProxy

为什么80%的码农都做不了架构师&#xff1f;>>> 因为.net core 的System.Net 中没有提供WebProxy这个方法,所以可以根据需求实现一个. public class CoreWebProxy : IWebProxy{public readonly Uri Uri;private readonly bool bypass;public CoreWebProxy(Uri uri,…

2015年08月

2015年07月 - 2015年09月 ● 一般而言。。。 一般而言&#xff0c;牙周病轻者有口臭、牙龈红肿疼痛、刷牙流血等症状&#xff0c;严重时会造成牙龈萎缩、牙齿敏感、牙齿摇动等情况。口腔没有在饮食后30分钟清洁就会逐渐转化为酸性环境&#xff08;PH值约5.5&#xff09;&#x…

scala case class 继承_数字硬件系统设计之一:Scala快速入门(2)

原想简单笼统介绍一下scala&#xff0c;后感觉这么做意思不大&#xff0c;网友看了和没看一样&#xff0c;还是应该稍微详细具体一点&#xff0c;故而把系列编号由(上)(中)(下)&#xff0c;改为(上)(2)(3)(4)(5)....,(上)就是(1)吧&#xff0c;以下内容部分节选于我们即将出版的…

crontab命令

前一天学习了 at 命令是针对仅运行一次的任务&#xff0c;循环运行的例行性计划任务&#xff0c;linux系统则是由 cron (crond) 这个系统服务来控制的。Linux 系统上面原本就有非常多的计划性工作&#xff0c;因此这个系统服务是默认启动的。另外, 由于使用者自己也可以设置计划…

求圆和椭圆上任意角度的点的坐标

圆上任意角度的点的坐标 如上图&#xff0c;给定圆心&#xff08;Cx,Cy&#xff09;,半径为R&#xff0c; 求θ\thetaθ对应的点的坐标&#xff1f; 此处θ\thetaθ是相对于水平轴的角度。 显然我们可以使用极坐标转换来求&#xff1a; {pxCxRcos(θ)pyCyRsin(θ)\left\{\begi…

smtp中mailfrom是必须的吗_你是住在高层建筑中吗?这是你必须了解的

01PARTONE消防电梯和普通客梯的作用及特点1.消防电梯是在建筑物发生火灾时供消防人员进行灭火与救援使用且具有一定功能的电梯。因此&#xff0c;消防电梯具有较高的防火要求&#xff0c;其防火设计十分重要。2.普通电梯均不具备消防功能&#xff0c;发生火灾时禁止人们搭乘电梯…

c++ 函数的值传递,引用传递 和 引用返回的探索

2019独角兽企业重金招聘Python工程师标准>>> 前言 C的函数参数和返回分为按值传递和按引用传递,应用到类上面,会涉及到类的 赋值操作 复制函数 构造函数 析构函数 虽然java开发了两年,但对我而言c我还只是一个初学者.c还有很多陌生的特性需要自己亲自探索.这里用实际…

GCD的部分总结

GCD是基于C语言的底层API,用Block定义任务用起来非常灵活便捷. GCD的基本思想是就将操作放在队列中去执行 (1)操作使用Blocks定义(2)队列负责调度任务执行所在的线程以及具体的执行时间(3)队列的特点是先进先出(FIFO)的&#xff0c;新添加至对列的操作都会排在队尾关于多线程的…

多线程编程2-NSOperation

本文目录 前言一、NSInvocationOperation二、NSBlockOperation三、NSOperation的其他用法四、自定义NSOperation回到顶部前言 1.上一讲简单介绍了NSThread的使用&#xff0c;虽然也可以实现多线程编程&#xff0c;但是需要我们去管理线程的生命周期&#xff0c;还要考虑线程同步…

闪回表操作语法+使用闪回删除

闪回表操作语法 flashback table 【 schema.】 table_name to {【before drop 【rename to new_table_name】 】|【scn | timestamp 】】 expr 【enable | disable 】 triggers}: 参数说明&#xff1a; schema&#xff1a;用户模式 before drop&#xff1a;表示恢复到删除…

欧拉函数 - HDU1286

欧拉函数的作用&#xff1a; 有[1,2.....n]这样一个集合&#xff0c;f(n)这个集合中与n互质的元素的个数。欧拉函数描述了一些列与这个f(n)有关的一些性质&#xff0c;如下&#xff1a; 1、令p为一个素数&#xff0c;n p ^ k&#xff0c;则 f(n) p ^ k - p ^ (k-1) 2、令m&…

其中一个页签慢_渭南提升一个大专学历的有效方法

渭南提升一个大专学历的有效方法&#xff0c;宏德教育&#xff0c;目前已形成以高等学历教育为特色王牌&#xff0c;职称考评、企业内训为辅助的强力优势品牌。渭南提升一个大专学历的有效方法&#xff0c; 获得发明专利或实用新型专利&#xff0c;且已实施取得效益。出版本专业…

《收集苹果》 动态规划入门

问题描写叙述 平面上有N*M个格子&#xff0c;每一个格子中放着一定数量的苹果。你从左上角的格子開始&#xff0c;每一步仅仅能向下走或是向右走&#xff0c;每次走到一个格子上就把格子里的苹果收集起来&#xff0c;这样下去&#xff0c;你最多能收集到多少个苹果。 输入&…

Xamarin XAML语言教程通过ProgressTo方法对进度条设置

2019独角兽企业重金招聘Python工程师标准>>> Xamarin XAML语言教程通过ProgressTo方法对进度条设置 在ProgressBar中定义了一个ProgressTo方法&#xff0c;此方法也可以用来对进度条当前的进行进行设置&#xff0c;ProgressTo与Progress属性的不同之处在于ProgressT…

h5新特性

 CSDN博客 Gane_ChengHTML5新特性浅谈 发表于2016/10/17 21:25:58 7809人阅读 分类&#xff1a; 前端 转载请注明出处&#xff1a; http://blog.csdn.net/gane_cheng/article/details/52819118 http://www.ganecheng.tech/blog/52819118.html &#xff08;浏览效果更好…

mysql日期截取年月_摄影大赛丨“我遇见最美的光”第五届全国医务人员摄影大展 截稿日期2020年8月15日...

截稿日期2020年8月15日《“我遇见最美的光”第五届全国医务人员摄影大展》欣赏过山川壮丽&#xff0c;瞻仰过造化旖旎&#xff0c;敬重于生命伟大&#xff0c;感动于英雄凯旋……由《大众摄影》主办&#xff0c;正大天晴药业集团股份有限公司、《中国卫生影像》杂志协办的“我遇…

Pytorch的C++接口实践

Pytorch1.1版本已经提供了相对稳定的c接口&#xff0c;网上也有了众多的资料供大家参考&#xff0c;进行c的接口的初步尝试。 可以按照对应的选项下载&#xff0c;下面我们要说的是&#xff1a; 如何利用已经编译好的官方libtorch库和其他的opencv库等联合编写应用&#xff1f…