Android 中加载图片的工作频繁且重复,找一款好的组件使用是很顺手的事情。开源框架 ImageLoader 用起来还不错,入门参考 http://blog.csdn.net/hhhccckkk/article/details/8898651
在项目中用了一段时间后,发现一些可以改进的地方:
(1)每次访问网络取图片,发现加载器总是会两次访问同一个地址,对于 GPRS 这样的蜗牛网速来说,这可不是什么好事。找找原因,起初以为是没有缓存在内存或SD卡,后来一一排除,原来是因为有段代码访问了两次,似乎开发者没有找到什么特别好的办法解决。本人尝试了几种办法,发现是可以改进的。
(2)我接受的方法是在 Application 中初始化加载器的时候要使用自己扩展的 ImageDecoder
protected void initImageCache() { /** * 初始化图片加载 */ Logger.d(TAG, "Initializing image loader."); File cacheDir = StorageUtils.getOwnCacheDirectory(getApplicationContext(), "myApplication/Cache"); ImageLoaderConfiguration.Builder builder = new ImageLoaderConfiguration.Builder(getApplicationContext()); builder.threadPoolSize(3); // 设置线程数量为3 builder.threadPriority(Thread.NORM_PRIORITY - 1); // 设定线程等级比普通低一点 builder.memoryCacheExtraOptions(200, 200); // 设定缓存在内存的图片大小最大为200x200 builder.memoryCache(new UsingFreqLimitedMemoryCache(2 * 1024 * 1024)); builder.discCache(new UnlimitedDiscCache(cacheDir)) ; builder.discCacheExtraOptions(displayMetrics.widthPixels, displayMetrics.heightPixels, CompressFormat.JPEG, 80, null); builder.denyCacheImageMultipleSizesInMemory(); // 拒绝缓存同一图片,有不同的大小 builder.discCacheFileNameGenerator(new Md5FileNameGenerator()); builder.imageDownloader(new MyImageLoader(getApplicationContext(),restClient));//new BaseImageDownloader(getApplicationContext()));// builder.imageDecoder(new MyImageDecoder(true)); builder.enableLogging(); // 开启调试 // 设置默认显示情况 DisplayImageOptions.Builder displayImageOptionsBuilder = new DisplayImageOptions.Builder(); displayImageOptionsBuilder.showImageForEmptyUri(R.drawable.house_icon_photo4); // 空uri的情况 displayImageOptionsBuilder.cacheInMemory(true); // 缓存在内存 displayImageOptionsBuilder.cacheOnDisc(true); // 缓存在磁盘 displayImageOptionsBuilder.imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2); builder.defaultDisplayImageOptions(displayImageOptionsBuilder.build()); ImageLoader.getInstance().init(builder.build()); Logger.d(TAG, "Initialize image loader finished."); }
(2)MyImageDecoder.java 扩展自 BaseImageDecoder
import java.io.IOException; import java.io.InputStream; import android.graphics.Bitmap; import android.graphics.BitmapFactory.Options; import myapp.sdk.io.CloseShieldInputStream; import com.nostra13.universalimageloader.core.assist.ImageSize; import com.nostra13.universalimageloader.core.decode.BaseImageDecoder; import com.nostra13.universalimageloader.core.decode.ImageDecodingInfo; import com.nostra13.universalimageloader.utils.L; public class MyImageDecoder extends BaseImageDecoder{ public MyImageDecoder(boolean loggingEnabled) { this.loggingEnabled = loggingEnabled; } @Override public Bitmap decode(ImageDecodingInfo decodingInfo) throws IOException { InputStream imageStream = getImageStream(decodingInfo); // inputStream mark imageStream.mark(imageStream.available()+1); InputStream imageStreamClone = new CloseShieldInputStream(imageStream); ImageFileInfo imageInfo = defineImageSizeAndRotation(imageStreamClone, decodingInfo.getImageUri()); Options decodingOptions = prepareDecodingOptions(imageInfo.imageSize, decodingInfo); // imageStream = getImageStream(decodingInfo);//michael remove double load from server // inputStream reset imageStream.reset(); Bitmap decodedBitmap = decodeStream(imageStream, decodingOptions); if (decodedBitmap == null) { L.e(ERROR_CANT_DECODE_IMAGE, decodingInfo.getImageKey()); } else { decodedBitmap = considerExactScaleAndOrientaiton(decodedBitmap, decodingInfo, imageInfo.exif.rotation, imageInfo.exif.flipHorizontal); } return decodedBitmap; } }
(3)CloseShieldInputStream.java 可以直接使用 apache common-io,但在 android 上为了克隆 InputStream 一点点功能,而引入整个 IO 包,100多KB,似乎不划算,所以单独复制了 IO 包中的几个文件:
import java.io.InputStream; /*** * Proxy stream that prevents the underlying input stream from being closed. * <p> * This class is typically used in cases where an input stream needs to be * passed to a component that wants to explicitly close the stream even if * more input would still be available to other components. * * @version $Id: CloseShieldInputStream.java 587913 2007-10-24 15:47:30Z niallp $ * @since Commons IO 1.4 */ public class CloseShieldInputStream extends ProxyInputStream { /*** * Creates a proxy that shields the given input stream from being * closed. * * @param in underlying input stream */ public CloseShieldInputStream(InputStream in) { super(in); } /*** * Replaces the underlying input stream with a {@link ClosedInputStream} * sentinel. The original input stream will remain open, but this proxy * will appear closed. */ public void close() { in = new ClosedInputStream(); } }
import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; /*** * A Proxy stream which acts as expected, that is it passes the method * calls on to the proxied stream and doesn't change which methods are * being called. * <p> * It is an alternative base class to FilterInputStream * to increase reusability, because FilterInputStream changes the * methods being called, such as read(byte[]) to read(byte[], int, int). * * @author Stephen Colebourne * @version $Id: ProxyInputStream.java 610010 2008-01-08 14:50:59Z niallp $ */ public abstract class ProxyInputStream extends FilterInputStream { /*** * Constructs a new ProxyInputStream. * * @param proxy the InputStream to delegate to */ public ProxyInputStream(InputStream proxy) { super(proxy); // the proxy is stored in a protected superclass variable named 'in' } /*** * Invokes the delegate's <code>read()</code> method. * @return the byte read or -1 if the end of stream * @throws IOException if an I/O error occurs */ public int read() throws IOException { return in.read(); } /*** * Invokes the delegate's <code>read(byte[])</code> method. * @param bts the buffer to read the bytes into * @return the number of bytes read or -1 if the end of stream * @throws IOException if an I/O error occurs */ public int read(byte[] bts) throws IOException { return in.read(bts); } /*** * Invokes the delegate's <code>read(byte[], int, int)</code> method. * @param bts the buffer to read the bytes into * @param st The start offset * @param end The number of bytes to read * @return the number of bytes read or -1 if the end of stream * @throws IOException if an I/O error occurs */ public int read(byte[] bts, int st, int end) throws IOException { return in.read(bts, st, end); } /*** * Invokes the delegate's <code>skip(long)</code> method. * @param ln the number of bytes to skip * @return the number of bytes to skipped or -1 if the end of stream * @throws IOException if an I/O error occurs */ public long skip(long ln) throws IOException { return in.skip(ln); } /*** * Invokes the delegate's <code>available()</code> method. * @return the number of available bytes * @throws IOException if an I/O error occurs */ public int available() throws IOException { return in.available(); } /*** * Invokes the delegate's <code>close()</code> method. * @throws IOException if an I/O error occurs */ public void close() throws IOException { in.close(); } /*** * Invokes the delegate's <code>mark(int)</code> method. * @param idx read ahead limit */ public synchronized void mark(int idx) { in.mark(idx); } /*** * Invokes the delegate's <code>reset()</code> method. * @throws IOException if an I/O error occurs */ public synchronized void reset() throws IOException { in.reset(); } /*** * Invokes the delegate's <code>markSupported()</code> method. * @return true if mark is supported, otherwise false */ public boolean markSupported() { return in.markSupported(); } }
import java.io.InputStream; /*** * Closed input stream. This stream returns -1 to all attempts to read * something from the stream. * <p> * Typically uses of this class include testing for corner cases in methods * that accept input streams and acting as a sentinel value instead of a * <code>null</code> input stream. * * @version $Id: ClosedInputStream.java 601751 2007-12-06 14:55:45Z niallp $ * @since Commons IO 1.4 */ public class ClosedInputStream extends InputStream { /*** * A singleton. */ public static final ClosedInputStream CLOSED_INPUT_STREAM = new ClosedInputStream(); /*** * Returns -1 to indicate that the stream is closed. * * @return always -1 */ public int read() { return -1; } }
(4)ImageLoader 会多次反复发送加载请求,对网络也是个灾难,在扩展的 MyImageLoader 中修改网络连接超时和读取网络超时的时间值
import android.content.Context; import com.nostra13.universalimageloader.core.download.BaseImageDownloader; public class MyImageLoader extends BaseImageDownloader { public MyImageLoader(Context context) { super(context,10000,60000); } }
相关推荐
《Android-universalimageloader的使用详解》 在Android应用开发中,图片加载与展示是一项不可或缺的任务,尤其在用户界面设计中,高质量的图片能够极大地提升用户体验。Android-universalimageloader是一个强大的...
UniversalImageLoader是一个专门为Android平台设计的高效、灵活的图片加载库。这个库旨在解决在Android应用中处理大量图片时可能出现的性能问题,如内存溢出(OOM)和UI线程阻塞。它提供了异步加载、内存和硬盘缓存...
总之,这个“android 获取网络图片(universalImageLoader 测试工程)”是一个很好的学习资源,它涵盖了Android中网络图片加载的基本流程,使用了强大的`UniversalImageLoader`库,并解决了ListView滚动时的图片加载...
修改universalimageloader,jar,解决图片路径中有https时Imageloader报出异常java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.使https图片完美显示
UniversalImageLoader是一个强大的开源图片加载库,特别适合在Android应用中使用,用于高效、便捷地加载网络图片。这个项目由Sergey Tarasevich开发,它提供了许多特性,包括缓存机制、线程管理、图片占位符以及错误...
android音乐播放器源码(改进版)。这个版本已经放在了service中,在服务中控制播放音乐,通过BroadcastReceiver传递一些数据,并且实现了在电话打过来时,停止播放音乐,打完电话继续播放。当然还有上一个版本的甩...
案例包含Android-Universal-Image-Loader 网络图片加载框架实现图片加载和结合universal-image-loader与LruCache来自定义缓存图片,可以设置缓存与不缓存。 博客地址:...
android 自定义百分比显示进度条(改进版),在原作者的基础上修改,改进的地方就是百分比文字显示在不同手机分辨率下进行处理,大家还可以继续在此基础上继续改进,本人主要使用在项目的系统版本更新,使用语法与原...
在Android开发中,串口通信(Serial Port Communication)是一种重要的技术,它允许设备之间通过串行接口进行数据交换。在Android Studio环境下实现串口通信,开发者可以构建与硬件设备交互的应用,例如读取传感器...
为了充分利用VB for Android,开发者需要掌握以下几个关键知识点: 1. **VB语法与Android API结合**:理解如何将VB的基本语句、控制结构、函数和类与Android SDK的API进行结合,创建原生的Android应用。 2. **布局...
通过这个"Android Test Project"小案例,你将有机会实践上述知识点,进一步熟悉Android Studio的使用,提升Android应用开发技能。记得在实践中不断探索,充分利用Android Studio的各项功能,为你的应用程序带来更...
Android Studio 3.5提供了更好的测试工具,包括JUnit5支持、 Espresso测试框架的改进和AndroidJUnitRunner的增强,使得单元测试和UI测试编写更加方便。 **8. Kotlin支持** Kotlin是Android开发的首选语言之一,3.5...
下面将详细介绍`android-21`中的关键知识点。 1. **Material Design**:Android Lollipop引入了全新的设计语言——Material Design,它强调层次感、响应式交互和动画效果。这一设计风格对界面元素、颜色、阴影以及...
这个版本的SDK包含了一系列重要的更新和改进,旨在提升性能、增强用户体验以及提供更多的开发功能。 1. **Android 8.1.0 (Oreo) 特性**: - **Background Execution Limitations**:Android 8.1对后台服务和后台...
在现代的移动应用开发中,JavaScript与原生平台之间的交互变得越来越常见,特别是在使用Android的WebView组件时。本文将深入探讨如何使用JavaScript调用Android的方法,并传递JSON数据,以实现两者之间的高效通信。 ...
扫雷游戏,作为一款经典的小游戏,它的实现过程涵盖了Android应用开发的多个核心知识点。 1. **Android Studio入门**:首先,你需要了解Android Studio的基本操作,包括创建新项目、项目结构、布局设计、代码编写...
UniversalImageLoader则是一个强大的图片加载、缓存库,特别适合在Android应用中处理大量图片的显示。它可以实现图片的异步加载,防止因加载图片导致的卡顿现象。UniversalImageLoader支持多种缓存策略,包括内存...
此版本4.0.1是Android Studio的重要更新之一,提供了许多新特性和改进,旨在提高开发者的生产力和用户体验。 首先,Android Studio 4.0.1在构建系统方面进行了优化。它支持Gradle插件6.1.1,这是一个强大的自动化...
在Android开发中,为UI元素添加虚线、圆角和渐变效果是常见的需求,可以提升应用的视觉吸引力。下面将详细讲解如何实现这些效果。 ### 一、虚线(Dashed Line) 在Android中,我们可以使用`Shape Drawable`来创建...