`

android universalimageloader 几点改进

 
阅读更多

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);
	}
}

 

分享到:
评论
2 楼 PassFeed_free 2013-07-17  
public Bitmap decode(ImageDecodingInfo decodingInfo) throws IOException 


到这个方法 ,getImageStream  都是读本地文件了, 并没有访问网络 


楼主用的是不是之前的版本 ?
1 楼 PassFeed_free 2013-07-16  
楼主你好, 请问这个库, 在大屏显示高清图片 ,listview 滑动多一段时间 .就会出现oom 求指导 

相关推荐

    Android-universalimageloader的使用

    universalimageloader的使用

    Android-UniversalImageLoader加载本地图片

    Universal Image Loader加载本地图片,解决GridView中checkbox乱序

    Android-Universal-Image-Loader示例

    Android UniversalImageLoader 异步加载图片

    android 获取网络图片(universalImageLoader 测试工程)

    android 获取网络图片是,使用第三方universalImageLoader开源工程!Eclipse改编,能跑通(listview 为圆形image图片).

    Android支持https的universalimageloader,jar

    修改universalimageloader,jar,解决图片路径中有https时Imageloader报出异常java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.使https图片完美显示

    android音乐播放器源码(改进版)

    android音乐播放器源码(改进版)。这个版本已经放在了service中,在服务中控制播放音乐,通过BroadcastReceiver传递一些数据,并且实现了在电话打过来时,停止播放音乐,打完电话继续播放。当然还有上一个版本的甩...

    Android之网络图片框架UniversalImageLoader和结合LruCache缓存图片

    案例包含Android-Universal-Image-Loader 网络图片加载框架实现图片加载和结合universal-image-loader与LruCache来自定义缓存图片,可以设置缓存与不缓存。 博客地址:...

    Android一个改进的进度条实例

    这是一个改进版的android进度条实例,本实例中,进度条在进度过程中,会在进度条中显示相应的进度百分比,而且该百分比的显示位置会根据你当前的进度点位置而自动变换位置,要么显示在左边,要么显示在右边,非常...

    android 自定义百分比显示进度条(改进版)

    android 自定义百分比显示进度条(改进版),在原作者的基础上修改,改进的地方就是百分比文字显示在不同手机分辨率下进行处理,大家还可以继续在此基础上继续改进,本人主要使用在项目的系统版本更新,使用语法与原...

    Android框架揭秘.pdf

    《Android框架揭秘》通过对Android系统源代码的分析,主要介绍Android框架的初始化过程及主要组件的工作原理。作者直接分析和整理了Android框架的主要源代码,并详细讲解了理解框架工作原理所需的各种基础知识和构成...

    Android串口通信(Android Studio)

    Android串口通信(Android Studio) serial Port 简单的demo 好久之前整的

    Android BLE蓝牙例子(包括android版Lightblue)实例源码

    源码里面有Bluetooth4_3/BLEDemo/Android_Lightblue.apk三个.前两个是BLE的demo。BLEDemo这个功能较Bluetooth4_3多一些,有兴趣的可以都看下。Android_Lightblue.apk是Android版的lightblue,在进行ble开发的时候用...

    Android 7.1.1 (API 25) SDK Platform 下载

    # mv /opt/android-sdk/platforms/android-25/android-7.1.1/* /opt/android-sdk/platforms/android-25/ # rm -rf /opt/android-sdk/platforms/android-25/android-7.1.1 官网下载地址:...

    Android40个经典源码

    31 android 加载时闪烁点样式的启动画面 32 基于 Android 的英文电子词典 33 android 源码之英语单词记忆程序源码 34 andorid 源码北京公交线路查询(离线) 35 Android 计算器源码 36 带文字的ProgressBar Demo源码...

    android viewpager 左右无限循环滑动 + 小圆点指示器

    android viewpager 实现了左右无限循环滑动 并且内附可自定义的小圆点指示器

    Android 8.0.0 (API 26) SDK Platform

    使用: export ANDROID_HOME="/opt/android-...# mv /opt/android-sdk/platforms/android-8.0.0 /opt/android-sdk/platforms/android-26 官网下载地址:https://dl.google.com/android/repository/platform-26_r01.zip

    android系统原理及开发要点详解

     第6~12章分模块介绍Android的几个核心系统,主要是本地框架和Java框架方面的内容,兼顾应用程序和驱动层,这是本书的重点。  第13章“Android应用程序概述及框架”,介绍Android应用程序层的基本概念和应用程序...

    Android扫雷游戏(基于Android Studio)

    基于Android平台的扫雷小游戏,使用Android Studio开发,附有简单注释,适用于初步掌握Android技术的程序猿们!

    Android组件设计思想

    Android应用开发的哲学是把一切都看作是组件。把应用程序组件化的好处是降低模块间的耦合性,同时提高模块的复用性。Android的组件设计思想与传统的组件设计思想最大的区别在于,前者不依赖于进程。也就是说,进程...

Global site tag (gtag.js) - Google Analytics