Android 开源框架Universal-Image-Loader完全解析(三)---源代码解读

Win10自动更新怎么永久关闭?有效的Win10强制更新关闭方法 之前小编为大家分享过一些Win10彻底关闭Windows Update自动更新的方法,主要是通过一些如设置流量计费或借助一些专门的小工具来实现,但往往会发现,Win10自动更新就像打不死的小强,不管怎么关闭,之后还是会自动更新,让不少小伙伴颇为不爽。今天小编带来了这篇改进型教程,通过全方位设置,彻底关闭Win10自动更新,感兴趣的小伙伴不妨试试吧。 ... 阅读详情
转载请注明本文出自xiaanming的博客( http://blog.youkuaiyun.com/xiaanming/article/details/39057201 ),请尊重他人的辛勤劳动成果,谢谢!

本篇文章主要是带大家从源码的角度上面去解读这个强大的图片加载框架,自己很久没有写文章了,感觉生疏了许多,距离上一篇文章三个月多了,确实是自己平常忙,换了工作很多东西都要去看去理解,然后加上自己也懒了,没有以前那么有激情了,我感觉这节奏不对,我要继续保持以前的激情,正所谓好记性不如烂笔头,有时候自己也会去翻看下之前写的东西,我觉得知识写下来比在脑海中留存的更久,今天就给大家来读一读这个框架的源码,我感觉这个图片加载框架确实写的很不错,读完代码自己也学到了很多。我希望大家可以先去看下Android 开源框架Universal-Image-Loader完全解析(一)--- 基本介绍及使用, Android 开源框架Universal-Image-Loader完全解析(二)--- 图片缓存策略详解 ,我希望大家可以坚持看完,看完了对你绝对是有收获的。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. ImageView mImageView = (ImageView) findViewById(R.id.image);    
  2.         String imageUrl = "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s1024/A%252520Photographer.jpg";    
  3.             
  4.         //显示图片的配置    
  5.         DisplayImageOptions options = new DisplayImageOptions.Builder()    
  6.                 .showImageOnLoading(R.drawable.ic_stub)    
  7.                 .showImageOnFail(R.drawable.ic_error)    
  8.                 .cacheInMemory(true)    
  9.                 .cacheOnDisk(true)    
  10.                 .bitmapConfig(Bitmap.Config.RGB_565)    
  11.                 .build();    
  12.             
  13.         ImageLoader.getInstance().displayImage(imageUrl, mImageView, options);    
大部分的时候我们都是使用上面的代码去加载图片,我们先看下

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. public void displayImage(String uri, ImageView imageView, DisplayImageOptions options) {  
  2.         displayImage(uri, new ImageViewAware(imageView), options, null, null);  
  3.     }  
从上面的代码中,我们可以看出,它会将ImageView转换成ImageViewAware, ImageViewAware主要是做什么的呢?该类主要是将ImageView进行一个包装,将ImageView的强引用变成弱引用,当内存不足的时候,可以更好的回收ImageView对象,还有就是获取ImageView的宽度和高度。这使得我们可以根据ImageView的宽高去对图片进行一个裁剪,减少内存的使用。

接下来看具体的displayImage方法啦,由于这个方法代码量蛮多的,所以这里我分开来读

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. checkConfiguration();  
  2.         if (imageAware == null) {  
  3.             throw new IllegalArgumentException(ERROR_WRONG_ARGUMENTS);  
  4.         }  
  5.         if (listener == null) {  
  6.             listener = emptyListener;  
  7.         }  
  8.         if (options == null) {  
  9.             options = configuration.defaultDisplayImageOptions;  
  10.         }  
  11.   
  12.         if (TextUtils.isEmpty(uri)) {  
  13.             engine.cancelDisplayTaskFor(imageAware);  
  14.             listener.onLoadingStarted(uri, imageAware.getWrappedView());  
  15.             if (options.shouldShowImageForEmptyUri()) {  
  16.                 imageAware.setImageDrawable(options.getImageForEmptyUri(configuration.resources));  
  17.             } else {  
  18.                 imageAware.setImageDrawable(null);  
  19.             }  
  20.             listener.onLoadingComplete(uri, imageAware.getWrappedView(), null);  
  21.             return;  
  22.         }  
第1行代码是检查ImageLoaderConfiguration是否初始化,这个初始化是在Application中进行的

12-21行主要是针对url为空的时候做的处理,第13行代码中,ImageLoaderEngine中存在一个HashMap,用来记录正在加载的任务,加载图片的时候会将ImageView的id和图片的url加上尺寸加入到HashMap中,加载完成之后会将其移除,然后将DisplayImageOptions的imageResForEmptyUri的图片设置给ImageView,最后回调给ImageLoadingListener接口告诉它这次任务完成了。

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. ImageSize targetSize = ImageSizeUtils.defineTargetSizeForView(imageAware, configuration.getMaxImageSize());  
  2.     String memoryCacheKey = MemoryCacheUtils.generateKey(uri, targetSize);  
  3.     engine.prepareDisplayTaskFor(imageAware, memoryCacheKey);  
  4.   
  5.     listener.onLoadingStarted(uri, imageAware.getWrappedView());  
  6.   
  7.     Bitmap bmp = configuration.memoryCache.get(memoryCacheKey);  
  8.     if (bmp != null && !bmp.isRecycled()) {  
  9.         L.d(LOG_LOAD_IMAGE_FROM_MEMORY_CACHE, memoryCacheKey);  
  10.   
  11.         if (options.shouldPostProcess()) {  
  12.             ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,  
  13.                     options, listener, progressListener, engine.getLockForUri(uri));  
  14.             ProcessAndDisplayImageTask displayTask = new ProcessAndDisplayImageTask(engine, bmp, imageLoadingInfo,  
  15.                     defineHandler(options));  
  16.             if (options.isSyncLoading()) {  
  17.                 displayTask.run();  
  18.             } else {  
  19.                 engine.submit(displayTask);  
  20.             }  
  21.         } else {  
  22.             options.getDisplayer().display(bmp, imageAware, LoadedFrom.MEMORY_CACHE);  
  23.             listener.onLoadingComplete(uri, imageAware.getWrappedView(), bmp);  
  24.         }  
  25.     }  
第1行主要是将ImageView的宽高封装成ImageSize对象,如果获取ImageView的宽高为0,就会使用手机屏幕的宽高作为ImageView的宽高,我们在使用ListView,GridView去加载图片的时候,第一页获取宽度是0,所以第一页使用的手机的屏幕宽高,后面的获取的都是控件本身的大小了

第7行从内存缓存中获取Bitmap对象,我们可以再ImageLoaderConfiguration中配置内存缓存逻辑,默认使用的是LruMemoryCache,这个类我在前面的文章中讲过

第11行中有一个判断,我们如果在DisplayImageOptions中设置了postProcessor就进入true逻辑,不过默认postProcessor是为null的,BitmapProcessor接口主要是对Bitmap进行处理,这个框架并没有给出相对应的实现,如果我们有自己的需求的时候可以自己实现BitmapProcessor接口(比如将图片设置成圆形的)

第22 -23行是将Bitmap设置到ImageView上面,这里我们可以在DisplayImageOptions中配置显示需求displayer,默认使用的是SimpleBitmapDisplayer,直接将Bitmap设置到ImageView上面,我们可以配置其他的显示逻辑, 他这里提供了FadeInBitmapDisplayer(透明度从0-1)RoundedBitmapDisplayer(4个角是圆弧)等, 然后回调到ImageLoadingListener接口

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. if (options.shouldShowImageOnLoading()) {  
  2.                 imageAware.setImageDrawable(options.getImageOnLoading(configuration.resources));  
  3.             } else if (options.isResetViewBeforeLoading()) {  
  4.                 imageAware.setImageDrawable(null);  
  5.             }  
  6.   
  7.             ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,  
  8.                     options, listener, progressListener, engine.getLockForUri(uri));  
  9.             LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(engine, imageLoadingInfo,  
  10.                     defineHandler(options));  
  11.             if (options.isSyncLoading()) {  
  12.                 displayTask.run();  
  13.             } else {  
  14.                 engine.submit(displayTask);  
  15.             }  
这段代码主要是Bitmap不在内存缓存,从文件中或者网络里面获取bitmap对象,实例化一个LoadAndDisplayImageTask对象,LoadAndDisplayImageTask实现了Runnable,如果配置了isSyncLoading为true, 直接执行LoadAndDisplayImageTask的run方法,表示同步,默认是false,将LoadAndDisplayImageTask提交给线程池对象

接下来我们就看LoadAndDisplayImageTask的run(), 这个类还是蛮复杂的,我们还是一段一段的分析

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. if (waitIfPaused()) return;  
  2. if (delayIfNeed()) return;  

如果waitIfPaused(), delayIfNeed()返回true的话,直接从run()方法中返回了,不执行下面的逻辑, 接下来我们先看看waitIfPaused()

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private boolean waitIfPaused() {  
  2.     AtomicBoolean pause = engine.getPause();  
  3.     if (pause.get()) {  
  4.         synchronized (engine.getPauseLock()) {  
  5.             if (pause.get()) {  
  6.                 L.d(LOG_WAITING_FOR_RESUME, memoryCacheKey);  
  7.                 try {  
  8.                     engine.getPauseLock().wait();  
  9.                 } catch (InterruptedException e) {  
  10.                     L.e(LOG_TASK_INTERRUPTED, memoryCacheKey);  
  11.                     return true;  
  12.                 }  
  13.                 L.d(LOG_RESUME_AFTER_PAUSE, memoryCacheKey);  
  14.             }  
  15.         }  
  16.     }  
  17.     return isTaskNotActual();  
  18. }  

这个方法是干嘛用呢,主要是我们在使用ListView,GridView去加载图片的时候,有时候为了滑动更加的流畅,我们会选择手指在滑动或者猛地一滑动的时候不去加载图片,所以才提出了这么一个方法,那么要怎么用呢?  这里用到了PauseOnScrollListener这个类,使用很简单ListView.setOnScrollListener(new PauseOnScrollListener(pauseOnScroll, pauseOnFling )), pauseOnScroll控制我们缓慢滑动ListView,GridView是否停止加载图片,pauseOnFling 控制猛的滑动ListView,GridView是否停止加载图片

除此之外,这个方法的返回值由isTaskNotActual()决定,我们接着看看isTaskNotActual()的源码

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private boolean isTaskNotActual() {  
  2.         return isViewCollected() || isViewReused();  
  3.     }  
isViewCollected()是判断我们ImageView是否被垃圾回收器回收了,如果回收了,LoadAndDisplayImageTask方法的run()就直接返回了,isViewReused()判断该ImageView是否被重用,被重用run()方法也直接返回,为什么要用isViewReused()方法呢?主要是ListView,GridView我们会复用item对象,假如我们先去加载ListView,GridView第一页的图片的时候,第一页图片还没有全部加载完我们就快速的滚动,isViewReused()方法就会避免这些不可见的item去加载图片,而直接加载当前界面的图片
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. ReentrantLock loadFromUriLock = imageLoadingInfo.loadFromUriLock;  
  2.         L.d(LOG_START_DISPLAY_IMAGE_TASK, memoryCacheKey);  
  3.         if (loadFromUriLock.isLocked()) {  
  4.             L.d(LOG_WAITING_FOR_IMAGE_LOADED, memoryCacheKey);  
  5.         }  
  6.   
  7.         loadFromUriLock.lock();  
  8.         Bitmap bmp;  
  9.         try {  
  10.             checkTaskNotActual();  
  11.   
  12.             bmp = configuration.memoryCache.get(memoryCacheKey);  
  13.             if (bmp == null || bmp.isRecycled()) {  
  14.                 bmp = tryLoadBitmap();  
  15.                 if (bmp == null) return; // listener callback already was fired  
  16.   
  17.                 checkTaskNotActual();  
  18.                 checkTaskInterrupted();  
  19.   
  20.                 if (options.shouldPreProcess()) {  
  21.                     L.d(LOG_PREPROCESS_IMAGE, memoryCacheKey);  
  22.                     bmp = options.getPreProcessor().process(bmp);  
  23.                     if (bmp == null) {  
  24.                         L.e(ERROR_PRE_PROCESSOR_NULL, memoryCacheKey);  
  25.                     }  
  26.                 }  
  27.   
  28.                 if (bmp != null && options.isCacheInMemory()) {  
  29.                     L.d(LOG_CACHE_IMAGE_IN_MEMORY, memoryCacheKey);  
  30.                     configuration.memoryCache.put(memoryCacheKey, bmp);  
  31.                 }  
  32.             } else {  
  33.                 loadedFrom = LoadedFrom.MEMORY_CACHE;  
  34.                 L.d(LOG_GET_IMAGE_FROM_MEMORY_CACHE_AFTER_WAITING, memoryCacheKey);  
  35.             }  
  36.   
  37.             if (bmp != null && options.shouldPostProcess()) {  
  38.                 L.d(LOG_POSTPROCESS_IMAGE, memoryCacheKey);  
  39.                 bmp = options.getPostProcessor().process(bmp);  
  40.                 if (bmp == null) {  
  41.                     L.e(ERROR_POST_PROCESSOR_NULL, memoryCacheKey);  
  42.                 }  
  43.             }  
  44.             checkTaskNotActual();  
  45.             checkTaskInterrupted();  
  46.         } catch (TaskCancelledException e) {  
  47.             fireCancelEvent();  
  48.             return;  
  49.         } finally {  
  50.             loadFromUriLock.unlock();  
  51.         }  
第1行代码有一个loadFromUriLock,这个是一个锁,获取锁的方法在ImageLoaderEngine类的getLockForUri()方法中
[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. ReentrantLock getLockForUri(String uri) {  
  2.         ReentrantLock lock = uriLocks.get(uri);  
  3.         if (lock == null) {  
  4.             lock = new ReentrantLock();  
  5.             uriLocks.put(uri, lock);  
  6.         }  
  7.         return lock;  
  8.     }  
从上面可以看出,这个锁对象与图片的url是相互对应的,为什么要这么做?也行你还有点不理解,不知道大家有没有考虑过一个场景,假如在一个ListView中,某个item正在获取图片的过程中,而此时我们将这个item滚出界面之后又将其滚进来,滚进来之后如果没有加锁,该item又会去加载一次图片,假设在很短的时间内滚动很频繁,那么就会出现多次去网络上面请求图片,所以这里根据图片的Url去对应一个ReentrantLock对象,让具有相同Url的请求就会在第7行等待,等到这次图片加载完成之后,ReentrantLock就被释放,刚刚那些相同Url的请求就会继续执行第7行下面的代码

来到第12行,它们会先从内存缓存中获取一遍,如果内存缓存中没有在去执行下面的逻辑,所以ReentrantLock的作用就是避免这种情况下重复的去从网络上面请求图片。

第14行的方法tryLoadBitmap(),这个方法确实也有点长,我先告诉大家,这里面的逻辑是先从文件缓存中获取有没有Bitmap对象,如果没有在去从网络中获取,然后将bitmap保存在文件系统中,我们还是具体分析下

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. File imageFile = configuration.diskCache.get(uri);  
  2.             if (imageFile != null && imageFile.exists()) {  
  3.                 L.d(LOG_LOAD_IMAGE_FROM_DISK_CACHE, memoryCacheKey);  
  4.                 loadedFrom = LoadedFrom.DISC_CACHE;  
  5.   
  6.                 checkTaskNotActual();  
  7.                 bitmap = decodeImage(Scheme.FILE.wrap(imageFile.getAbsolutePath()));  
  8.             }  
先判断文件缓存中有没有该文件,如果有的话,直接去调用decodeImage()方法去解码图片,该方法里面调用BaseImageDecoder类的decode()方法,根据ImageView的宽高,ScaleType去裁剪图片,具体的代码我就不介绍了,大家自己去看看,我们接下往下看tryLoadBitmap()方法

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. if (bitmap == null || bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {  
  2.             L.d(LOG_LOAD_IMAGE_FROM_NETWORK, memoryCacheKey);  
  3.             loadedFrom = LoadedFrom.NETWORK;  
  4.   
  5.             String imageUriForDecoding = uri;  
  6.             if (options.isCacheOnDisk() && tryCacheImageOnDisk()) {  
  7.                 imageFile = configuration.diskCache.get(uri);  
  8.                 if (imageFile != null) {  
  9.                     imageUriForDecoding = Scheme.FILE.wrap(imageFile.getAbsolutePath());  
  10.                 }  
  11.             }  
  12.   
  13.             checkTaskNotActual();  
  14.             bitmap = decodeImage(imageUriForDecoding);  
  15.   
  16.             if (bitmap == null || bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {  
  17.                 fireFailEvent(FailType.DECODING_ERROR, null);  
  18.             }  
  19.         }  
第1行表示从文件缓存中获取的Bitmap为null,或者宽高为0,就去网络上面获取Bitmap,来到第6行代码是否配置了DisplayImageOptions的isCacheOnDisk,表示是否需要将Bitmap对象保存在文件系统中,一般我们需要配置为true, 默认是false这个要注意下,然后就是执行tryCacheImageOnDisk()方法,去服务器上面拉取图片并保存在本地文件中

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. private Bitmap decodeImage(String imageUri) throws IOException {  
  2.     ViewScaleType viewScaleType = imageAware.getScaleType();  
  3.     ImageDecodingInfo decodingInfo = new ImageDecodingInfo(memoryCacheKey, imageUri, uri, targetSize, viewScaleType,  
  4.             getDownloader(), options);  
  5.     return decoder.decode(decodingInfo);  
  6. }  
  7.   
  8. /** @return <b>true</b> - if image was downloaded successfully; <b>false</b> - otherwise */  
  9. private boolean tryCacheImageOnDisk() throws TaskCancelledException {  
  10.     L.d(LOG_CACHE_IMAGE_ON_DISK, memoryCacheKey);  
  11.   
  12.     boolean loaded;  
  13.     try {  
  14.         loaded = downloadImage();  
  15.         if (loaded) {  
  16.             int width = configuration.maxImageWidthForDiskCache;  
  17.             int height = configuration.maxImageHeightForDiskCache;  
  18.               
  19.             if (width > 0 || height > 0) {  
  20.                 L.d(LOG_RESIZE_CACHED_IMAGE_FILE, memoryCacheKey);  
  21.                 resizeAndSaveImage(width, height); // TODO : process boolean result  
  22.             }  
  23.         }  
  24.     } catch (IOException e) {  
  25.         L.e(e);  
  26.         loaded = false;  
  27.     }  
  28.     return loaded;  
  29. }  
  30.   
  31. private boolean downloadImage() throws IOException {  
  32.     InputStream is = getDownloader().getStream(uri, options.getExtraForDownloader());  
  33.     return configuration.diskCache.save(uri, is, this);  
  34. }  
第6行的downloadImage()方法是负责下载图片,并将其保持到文件缓存中,将下载保存Bitmap的进度回调到IoUtils.CopyListener接口的onBytesCopied(int current, int total)方法中,所以我们可以设置ImageLoadingProgressListener接口来获取图片下载保存的进度,这里保存在文件系统中的图片是原图

第16-17行,获取ImageLoaderConfiguration是否设置保存在文件系统中的图片大小,如果设置了maxImageWidthForDiskCache和maxImageHeightForDiskCache,会调用resizeAndSaveImage()方法对图片进行裁剪然后在替换之前的原图,保存裁剪后的图片到文件系统的,之前有同学问过我说这个框架保存在文件系统的图片都是原图,怎么才能保存缩略图,只要在Application中实例化ImageLoaderConfiguration的时候设置maxImageWidthForDiskCache和maxImageHeightForDiskCache就行了

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. if (bmp == null) return; // listener callback already was fired  
  2.   
  3.                 checkTaskNotActual();  
  4.                 checkTaskInterrupted();  
  5.   
  6.                 if (options.shouldPreProcess()) {  
  7.                     L.d(LOG_PREPROCESS_IMAGE, memoryCacheKey);  
  8.                     bmp = options.getPreProcessor().process(bmp);  
  9.                     if (bmp == null) {  
  10.                         L.e(ERROR_PRE_PROCESSOR_NULL, memoryCacheKey);  
  11.                     }  
  12.                 }  
  13.   
  14.                 if (bmp != null && options.isCacheInMemory()) {  
  15.                     L.d(LOG_CACHE_IMAGE_IN_MEMORY, memoryCacheKey);  
  16.                     configuration.memoryCache.put(memoryCacheKey, bmp);  
  17.                 }  
接下来这里就简单了,6-12行是否要对Bitmap进行处理,这个需要自行实现,14-17就是将图片保存到内存缓存中去

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. DisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(bmp, imageLoadingInfo, engine, loadedFrom);  
  2.         runTask(displayBitmapTask, syncLoading, handler, engine);  
最后这两行代码就是一个显示任务,直接看DisplayBitmapTask类的run()方法

[java]  view plain copy 在CODE上查看代码片 派生到我的代码片
  1. @Override  
  2.     public void run() {  
  3.         if (imageAware.isCollected()) {  
  4.             L.d(LOG_TASK_CANCELLED_IMAGEAWARE_COLLECTED, memoryCacheKey);  
  5.             listener.onLoadingCancelled(imageUri, imageAware.getWrappedView());  
  6.         } else if (isViewWasReused()) {  
  7.             L.d(LOG_TASK_CANCELLED_IMAGEAWARE_REUSED, memoryCacheKey);  
  8.             listener.onLoadingCancelled(imageUri, imageAware.getWrappedView());  
  9.         } else {  
  10.             L.d(LOG_DISPLAY_IMAGE_IN_IMAGEAWARE, loadedFrom, memoryCacheKey);  
  11.             displayer.display(bitmap, imageAware, loadedFrom);  
  12.             engine.cancelDisplayTaskFor(imageAware);  
  13.             listener.onLoadingComplete(imageUri, imageAware.getWrappedView(), bitmap);  
  14.         }  
  15.     }  

假如ImageView被回收了或者被重用了,回调给ImageLoadingListener接口,否则就调用BitmapDisplayer去显示Bitmap

文章写到这里就已经写完了,不知道大家对这个开源框架有没有进一步的理解,这个开源框架设计也很灵活,用了很多的设计模式,比如建造者模式,装饰模式,代理模式,策略模式等等,这样方便我们去扩展,实现我们想要的功能,今天的讲解就到这了,有对这个框架不明白的地方可以在下面留言,我会尽量为大家解答的。

液晶屏LVDS接口:【图文详讲】 ​LVDS(Low Voltage Differential Signaling,即低电压差分信号)接口又称RS-644总线接口,是20世纪90年代才提出的一种数据传输和接口技术。LVDS接口是美国NS美国国家半导体公司为克服以TTL电平方式传输宽带高码率数据时功耗大,电磁干扰大等缺点而研制的一种数字视频信号传输方式 阅读详情

相关推荐

Windows应急响应实战:灰鸽子木马检测与清除全流程解析

远程控制木马(RAT)是一种基于客户端/服务器(C/S)架构的恶意软件,攻击者通过它能够远程操控受害主机,实现屏幕监控、文件窃取、键盘记录等操作,对个人隐私与企业数据安全构成严重威胁。其技术原理通常涉及进程注入、网络通信、持久化机制等核心环节,在应急响应中具有极高的分析价值。掌握此类木马的检测与清除方法,是Windows系统安全防护与事件处置的基本功。本文以经典的灰鸽子木马为例,结合进程分析、网络排查、注册表检查等实战技术,系统讲解从行为识别、痕迹取证到彻底清除的完整操作流程,并涵盖Rootkit对抗、无文

weixin_30521161的博客 415

万能imageLoader加载图片的包装,直接用

ImageLoader 是android一款牛逼的开源项目,为了大家能更方便的使用,我在这里分别对 1:加载网络图片 2:加载drwable目录图片 3:加载assert目录的图片 4:加载相册图片 等模块进行了封装: import android.widget.ImageView; import com.nostra13.universalimageloader.core.Dis

小炫风技术旅行 1692

淘宝电商产品价格官方防爬取采集设计机制,如何破?|淘宝电商API数据采集看完你也会!

然而,随着电子商务的蓬勃发展,涌现出大量的第三方工具和应用,试图通过采集淘宝电商产品价格等信息来进行数据分析和竞争优势的获取。为了维护市场秩序和保护商家权益,淘宝采取了一系列的防爬取设计机制,以阻止非授权的数据采集行为。为了确保数据的准确性和及时性,淘宝采取了多层次的防爬取机制,以限制未经授权的数据采集。其它的情况,比如淘宝首页、淘宝关键词商品搜索结果页面、商品详情页面,都是正常展示,未实现加密;也可以使用【tesseract ocr识别】指令,这个是免费无限使用的;【淘宝商品搜索结果页面-本地截图】

TinagirlAPI的博客 1389

ImageLoader动态获取网络图片

ImageLoader动态获取网络图片 新建类,继承Application import android.app.Application; import com.nostra13.universalimageloader.core.ImageLoader; import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;...

weixin_42791904的博客 472

Yolov26 在 Rk3588 上的 Rknn Onnx 部署实践(c++)

本文介绍了YOLOv26在RK3588平台的C++推理部署方案。重点包括:1)扩展Ultralytics导出格式,新增RKNN_ONNX专用导出选项;2)重构Detect Head结构,使其更适合RKNN推理;3)提供C++侧后处理实现建议。该方案保留了Ultralytics训练生态,通过优化模型结构输出,将解码等操作移至C++端,充分发挥Rockchip NPU性能。适用于RK3588/RK356x等平台,需配合rknn-toolkit2使用,为YOLOv26的嵌入式部署提供完整解决方案。

qq_64366203的博客 2178

MoveIt避障规划实战:从点云到OctoMap的环境感知全流程

本文详细解析了MoveIt避障规划中从点云到OctoMap的环境感知全流程,重点介绍了深度相机选型、点云数据处理、OctoMap生成及避障规划参数调优等关键技术。通过实战案例展示了如何利用MoveIt和OctoMap实现机械臂在复杂环境中的高效避障,为工业自动化和服务机器人开发提供实用解决方案。

weixin_30417487的博客 569

Universal-Image-Loader 源码的一些理解和分析

这个是一个非常好用的图片加载框架,虽然作者没有再维护了,但是我们项目中还是一直在使用,并且也很稳定。既然用到了该框架,那么是时候去看看该源码和学习学习。 源码地址:https://github.com/nostra13/Android-Universal-Image-Loader 一.整体架构: 先说怎么看整个源码:我是根据下面这种图开始看的,另外,我觉得作者源码包的分类也非常明确清晰,这个...

huang_xiao_yu的博客 973

android 开源框架Universal-Image-Loader完全解析(三)---源代码解读

本篇文章主要是带大家从源码的角度上面去解读这个强大的图片加载框架,自己很久没有写文章了,感觉生疏了许多,距离上一篇文章三个月多了,确实是自己平常忙,换了工作很多东西都要去看去理解,然后加上自己也懒了,没有以前那么有激情了,我感觉这节奏不对,我要继续保持以前的激情,正所谓好记性不如烂笔头,有时候自己也会去翻看下之前写的东西,我觉得知识写下来比在脑海中留存的更久,今天就给大家来读一读这个框架的源码,我

Code-lover's Learning Notes 919

ESP32-C3模组上实现蓝牙BLE配网功能(1)

ESP32-C3模组上实现蓝牙BLE配网功能(1)

phmatthaus的专栏 2280

华为OD机试真题 新系统2026-04-01 Python&JS【计算数列位置N的值】

如果其前面的M个元素中,存在值相同的元素,则该位置上的数值等于前面M个数中最大的数值与最小的数值之如果其前面的M个元素中,不存在值相同的元素,则该位置上的数值等于前面M个数中最大的数值与最小的数值之差;1、输入M、N两个数,则按照以下规则形成一个数列;两个整数,用逗号分割,分别表示M和N。一个整数,表示数列第N个位置上的数值。2、数列的前M个元素的值为1到M;请计算该数列第N个位置上的数值。N取值范围:1<= N<=50。M取值范围:3<=M<=10。

MISAYAONE的博客 3253

转:Android 开源框架Universal-Image-Loader完全解析(三)---源代码解读

转载请注明本文出自xiaanming的博客(http://blog.youkuaiyun.com/xiaanming/article/details/39057201),请尊重他人的辛勤劳动成果,谢谢! 本篇文章主要是带大家从源码的角度上面去解读这个强大的图片加载框架,自己很久没有写文章了,感觉生疏了许多,距离上一篇文章三个月多了,确实是自己平常忙,换了工作很多东西都要去看去理解,然后加上自己也懒了

fancychendong的专栏 1261

[Dify实战] 多轮对话状态管理:上下文保持与槽位填充

本文探讨了基于LLM的对话应用中多轮对话状态管理的核心挑战与解决方案。文章指出,单纯的"能聊"远远不够,关键在于建立有效的状态管理机制,包括上下文保持和槽位填充两大核心能力。通过Dify实战视角,详细阐述了如何设计工程化落地方案:采用混合策略的上下文管理(窗口+摘要+关键槽位)、JSON Schema强约束的槽位抽取、统一状态对象存储、冲突处理机制和优化追问策略。文章特别强调,合理的状态管理能将"聊天"转化为"可执行的业务流程",避免模型成为&qu

技术小甜甜:传播可落地技术,帮助个人和企业降低解决真实场景问题的成本 242
上一篇: Android 开源框架Universal-Image-Loader完全解析(二)--- 图片缓存策略详解
下一篇: Android Resource介绍和使用
codepython
博客等级 码龄20年 125粉丝 6原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值