Android 开源框架Universal-Image-Loader全然解析(一)--- 基本介绍及使用

大家好!差点儿相同两个来月没有写文章了。前段时间也是在忙换工作的事,准备笔试面试什么的事情,如今新工作找好了,新工作自己也比較惬意。唯一遗憾的就是自己要去一个新的城市,新的环境新的開始。希望自己能尽快的适应新环境,如今在准备交接的事情,自己也有一些时间了,所以就继续给大家分享Android方面的东西。

相信大家平时做Android应用的时候,多少会接触到异步载入图片,或者载入大量图片的问题。而载入图片我们常常会遇到很多的问题,比方说图片的错乱。OOM等问题,对于新手来说,这些问题解决起来会比較吃力,所以就有非常多的开源图片载入框架应运而生,比較著名的就是Universal-Image-Loader。相信非常多朋友都听过或者使用过这个强大的图片载入框架,今天这篇文章就是对这个框架的基本介绍以及使用,主要是帮助那些没有使用过这个框架的朋友们。

该项目存在于Github上面https://github.com/nostra13/Android-Universal-Image-Loader,我们能够先看看这个开源库存在哪些特征

  1. 多线程下载图片。图片能够来源于网络,文件系统,项目文件夹assets中以及drawable中等
  2. 支持任意的配置ImageLoader,比如线程池,图片下载器。内存缓存策略,硬盘缓存策略。图片显示选项以及其它的一些配置
  3. 支持图片的内存缓存,文件系统缓存或者SD卡缓存
  4. 支持图片下载过程的监听
  5. 依据控件(ImageView)的大小对Bitmap进行裁剪。降低Bitmap占用过多的内存
  6. 较好的控制图片的载入过程,比如暂停图片载入,又一次開始载入图片,一般使用在ListView,GridView中,滑动过程中暂停载入图片,停止滑动的时候去载入图片
  7. 提供在较慢的网络下对图片进行载入

当然上面列举的特性可能不全,要想了解一些其它的特性仅仅能通过我们的使用慢慢去发现了,接下来我们就看看这个开源库的简单使用吧

新建一个Android项目,下载JAR包加入到projectlibs文件夹下

新建一个MyApplication继承Application,并在onCreate()中创建ImageLoader的配置參数,并初始化到ImageLoader中代码例如以下

package com.example.uil;

import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;

import android.app.Application;

public class MyApplication extends Application {

	@Override
	public void onCreate() {
		super.onCreate();

		//创建默认的ImageLoader配置參数
		ImageLoaderConfiguration configuration = ImageLoaderConfiguration
				.createDefault(this);

		//Initialize ImageLoader with configuration.
		ImageLoader.getInstance().init(configuration);
	}

}

ImageLoaderConfiguration是图片载入器ImageLoader的配置參数,使用了建造者模式,这里是直接使用了createDefault()方法创建一个默认的ImageLoaderConfiguration,当然我们还能够自己设置ImageLoaderConfiguration。设置例如以下

File cacheDir = StorageUtils.getCacheDirectory(context);
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
        .memoryCacheExtraOptions(480, 800) // default = device screen dimensions
        .diskCacheExtraOptions(480, 800, CompressFormat.JPEG, 75, null)
        .taskExecutor(...)
        .taskExecutorForCachedImages(...)
        .threadPoolSize(3) // default
        .threadPriority(Thread.NORM_PRIORITY - 1) // default
        .tasksProcessingOrder(QueueProcessingType.FIFO) // default
        .denyCacheImageMultipleSizesInMemory()
        .memoryCache(new LruMemoryCache(2 * 1024 * 1024))
        .memoryCacheSize(2 * 1024 * 1024)
        .memoryCacheSizePercentage(13) // default
        .diskCache(new UnlimitedDiscCache(cacheDir)) // default
        .diskCacheSize(50 * 1024 * 1024)
        .diskCacheFileCount(100)
        .diskCacheFileNameGenerator(new HashCodeFileNameGenerator()) // default
        .imageDownloader(new BaseImageDownloader(context)) // default
        .imageDecoder(new BaseImageDecoder()) // default
        .defaultDisplayImageOptions(DisplayImageOptions.createSimple()) // default
        .writeDebugLogs()
        .build();

上面的这些就是全部的选项配置。我们在项目中不须要每个都自己设置,一般使用createDefault()创建的ImageLoaderConfiguration就能使用,然后调用ImageLoader的init()方法将ImageLoaderConfiguration參数传递进去,ImageLoader使用单例模式。

配置Android Manifest文件

<manifest>
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- Include next permission if you want to allow UIL to cache images on SD card -->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    ...
    <application android:name="MyApplication">
        ...
    </application>
</manifest>

接下来我们就能够来载入图片了,首先我们定义好Activity的布局文件

<?xml version="1.0" encoding="utf-8"?

>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <ImageView
        android:layout_gravity="center"
        android:id="@+id/image"
        android:src="@drawable/ic_empty"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</FrameLayout>

里面仅仅有一个ImageView,非常easy,接下来我们就去载入图片。我们会发现ImageLader提供了几个图片载入的方法,主要是这几个displayImage(), loadImage(),loadImageSync()。loadImageSync()方法是同步的,android4.0有个特性。网络操作不能在主线程,所以loadImageSync()方法我们就不去使用

.

loadimage()载入图片

我们先使用ImageLoader的loadImage()方法来载入网络图片

final ImageView mImageView = (ImageView) findViewById(R.id.image);
		String imageUrl = "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s1024/A%252520Photographer.jpg";

		ImageLoader.getInstance().loadImage(imageUrl, new ImageLoadingListener() {

			@Override
			public void onLoadingStarted(String imageUri, View view) {

			}

			@Override
			public void onLoadingFailed(String imageUri, View view,
					FailReason failReason) {

			}

			@Override
			public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
				mImageView.setImageBitmap(loadedImage);
			}

			@Override
			public void onLoadingCancelled(String imageUri, View view) {

			}
		});

传入图片的url和ImageLoaderListener, 在回调方法onLoadingComplete()中将loadedImage设置到ImageView上面即可了,假设你认为传入ImageLoaderListener太复杂了,我们能够使用SimpleImageLoadingListener类,该类提供了ImageLoaderListener接口方法的空实现,使用的是缺省适配器模式

final ImageView mImageView = (ImageView) findViewById(R.id.image);
		String imageUrl = "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s1024/A%252520Photographer.jpg";

		ImageLoader.getInstance().loadImage(imageUrl, new SimpleImageLoadingListener(){

			@Override
			public void onLoadingComplete(String imageUri, View view,
					Bitmap loadedImage) {
				super.onLoadingComplete(imageUri, view, loadedImage);
				mImageView.setImageBitmap(loadedImage);
			}

		});

假设我们要指定图片的大小该怎么办呢,这也好办,初始化一个ImageSize对象,指定图片的宽和高。代码例如以下

final ImageView mImageView = (ImageView) findViewById(R.id.image);
		String imageUrl = "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s1024/A%252520Photographer.jpg";

		ImageSize mImageSize = new ImageSize(100, 100);

		ImageLoader.getInstance().loadImage(imageUrl, mImageSize, new SimpleImageLoadingListener(){

			@Override
			public void onLoadingComplete(String imageUri, View view,
					Bitmap loadedImage) {
				super.onLoadingComplete(imageUri, view, loadedImage);
				mImageView.setImageBitmap(loadedImage);
			}

		});

上面仅仅是非常easy的使用ImageLoader来载入网络图片,在实际的开发中,我们并不会这么使用,那我们寻常会怎么使用呢?我们会用到DisplayImageOptions。他能够配置一些图片显示的选项,比方图片在载入中ImageView显示的图片,是否须要使用内存缓存,是否须要使用文件缓存等等。可供我们选择的配置例如以下

DisplayImageOptions options = new DisplayImageOptions.Builder()
        .showImageOnLoading(R.drawable.ic_stub) // resource or drawable
        .showImageForEmptyUri(R.drawable.ic_empty) // resource or drawable
        .showImageOnFail(R.drawable.ic_error) // resource or drawable
        .resetViewBeforeLoading(false)  // default
        .delayBeforeLoading(1000)
        .cacheInMemory(false) // default
        .cacheOnDisk(false) // default
        .preProcessor(...)
        .postProcessor(...)
        .extraForDownloader(...)
        .considerExifParams(false) // default
        .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default
        .bitmapConfig(Bitmap.Config.ARGB_8888) // default
        .decodingOptions(...)
        .displayer(new SimpleBitmapDisplayer()) // default
        .handler(new Handler()) // default
        .build();

我们将上面的代码略微改动下

final ImageView mImageView = (ImageView) findViewById(R.id.image);
		String imageUrl = "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s1024/A%252520Photographer.jpg";
		ImageSize mImageSize = new ImageSize(100, 100);

		//显示图片的配置
		DisplayImageOptions options = new DisplayImageOptions.Builder()
				.cacheInMemory(true)
				.cacheOnDisk(true)
				.bitmapConfig(Bitmap.Config.RGB_565)
				.build();

		ImageLoader.getInstance().loadImage(imageUrl, mImageSize, options, new SimpleImageLoadingListener(){

			@Override
			public void onLoadingComplete(String imageUri, View view,
					Bitmap loadedImage) {
				super.onLoadingComplete(imageUri, view, loadedImage);
				mImageView.setImageBitmap(loadedImage);
			}

		});

我们使用了DisplayImageOptions来配置显示图片的一些选项。这里我加入了将图片缓存到内存中已经缓存图片到文件系统中,这样我们就不用操心每次都从网络中去载入图片了,是不是非常方便呢,可是DisplayImageOptions选项中有些选项对于loadImage()方法是无效的。比方showImageOnLoading, showImageForEmptyUri等,

displayImage()载入图片

接下来我们就来看看网络图片载入的还有一个方法displayImage(),代码例如以下

final ImageView mImageView = (ImageView) findViewById(R.id.image);
		String imageUrl = "https://lh6.googleusercontent.com/-55osAWw3x0Q/URquUtcFr5I/AAAAAAAAAbs/rWlj1RUKrYI/s1024/A%252520Photographer.jpg";

		//显示图片的配置
		DisplayImageOptions options = new DisplayImageOptions.Builder()
				.showImageOnLoading(R.drawable.ic_stub)
				.showImageOnFail(R.drawable.ic_error)
				.cacheInMemory(true)
				.cacheOnDisk(true)
				.bitmapConfig(Bitmap.Config.RGB_565)
				.build();

		ImageLoader.getInstance().displayImage(imageUrl, mImageView, options);

从上面的代码中,我们能够看出,使用displayImage()比使用loadImage()方便非常多,也不须要加入ImageLoadingListener接口,我们也不须要手动设置ImageView显示Bitmap对象。直接将ImageView作为參数传递到displayImage()中即可了,图片显示的配置选项中,我们加入了一个图片载入中ImageVIew上面显示的图片。以及图片载入出现错误显示的图片。效果例如以下,刚開始显示ic_stub图片,假设图片载入成功显示图片。载入产生错误显示ic_error

这种方法使用起来比較方便,并且使用displayImage()方法 他会依据控件的大小和imageScaleType来自己主动裁剪图片,我们改动下MyApplication,开启Log打印

public class MyApplication extends Application {

	@Override
	public void onCreate() {
		super.onCreate();

		//创建默认的ImageLoader配置參数
		ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(this)
		.writeDebugLogs() //打印log信息
		.build();

		//Initialize ImageLoader with configuration.
		ImageLoader.getInstance().init(configuration);
	}

}

我们来看下图片载入的Log信息

第一条信息中。告诉我们開始载入图片,打印出图片的url以及图片的最大宽度和高度,图片的宽高默认是设备的宽高,当然假设我们非常清楚图片的大小,我们也能够去设置这个大小,在ImageLoaderConfiguration的选项中memoryCacheExtraOptions(int maxImageWidthForMemoryCache, int maxImageHeightForMemoryCache)

第二条信息显示我们载入的图片来源于网络

第三条信息显示图片的原始大小为1024 x 682 经过裁剪变成了512 x 341

第四条显示图片加入到了内存缓存中,我这里没有加入到sd卡中,所以没有加入文件缓存的Log

我们在载入网络图片的时候。常常有须要显示图片下载进度的需求。Universal-Image-Loader当然也提供这种功能,仅仅须要在displayImage()方法中传入ImageLoadingProgressListener接口即可了。代码例如以下

imageLoader.displayImage(imageUrl, mImageView, options, new SimpleImageLoadingListener(), new ImageLoadingProgressListener() {

			@Override
			public void onProgressUpdate(String imageUri, View view, int current,
					int total) {

			}
		});

由于displayImage()方法中带ImageLoadingProgressListener參数的方法都有带ImageLoadingListener參数,所以我这里直接new 一个SimpleImageLoadingListener,然后我们就能够在回调方法onProgressUpdate()得到图片的载入进度。

载入其它来源的图片

使用Universal-Image-Loader框架不仅能够载入网络图片,还能够载入sd卡中的图片,Content provider等,使用也非常easy,仅仅是将图片的url稍加的改变下即可了,以下是载入文件系统的图片

//显示图片的配置
		DisplayImageOptions options = new DisplayImageOptions.Builder()
				.showImageOnLoading(R.drawable.ic_stub)
				.showImageOnFail(R.drawable.ic_error)
				.cacheInMemory(true)
				.cacheOnDisk(true)
				.bitmapConfig(Bitmap.Config.RGB_565)
				.build();

		final ImageView mImageView = (ImageView) findViewById(R.id.image);
		String imagePath = "/mnt/sdcard/image.png";
		String imageUrl = Scheme.FILE.wrap(imagePath);

//		String imageUrl = "http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg";

		imageLoader.displayImage(imageUrl, mImageView, options);

当然还有来源于Content provider,drawable,assets中。使用的时候也非常easy,我们仅仅须要给每个图片来源的地方加上Scheme包裹起来(Content provider除外)。然后当做图片的url传递到imageLoader中。Universal-Image-Loader框架会依据不同的Scheme获取到输入流

//图片来源于Content provider
		String contentprividerUrl = "content://media/external/audio/albumart/13";

		//图片来源于assets
		String assetsUrl = Scheme.ASSETS.wrap("image.png");

		//图片来源于
		String drawableUrl = Scheme.DRAWABLE.wrap("R.drawable.image");

GirdView,ListView载入图片


相信大部分人都是使用GridView,ListView来显示大量的图片。而当我们高速滑动GridView。ListView。我们希望能停止图片的载入,而在GridView,ListView停止滑动的时候载入当前界面的图片,这个框架当然也提供这个功能,使用起来也非常easy。它提供了PauseOnScrollListener这个类来控制ListView,GridView滑动过程中停止去载入图片,该类使用的是代理模式

listView.setOnScrollListener(new PauseOnScrollListener(imageLoader, pauseOnScroll, pauseOnFling));
		gridView.setOnScrollListener(new PauseOnScrollListener(imageLoader, pauseOnScroll, pauseOnFling));

第一个參数就是我们的图片载入对象ImageLoader, 第二个是控制是否在滑动过程中暂停载入图片。假设须要暂停传true即可了,第三个參数控制猛的滑动界面的时候图片是否载入

OutOfMemoryError


尽管这个框架有非常好的缓存机制,有效的避免了OOM的产生,一般的情况下产生OOM的概率比較小,可是并不能保证OutOfMemoryError永远不发生,这个框架对于OutOfMemoryError做了简单的catch,保证我们的程序遇到OOM而不被crash掉。可是假设我们使用该框架常常发生OOM,我们应该怎么去改善呢?

  • 降低线程池中线程的个数。在ImageLoaderConfiguration中的(.threadPoolSize)中配置,推荐配置1-5
  • 在DisplayImageOptions选项中配置bitmapConfig为Bitmap.Config.RGB_565,由于默认是ARGB_8888, 使用RGB_565会比使用ARGB_8888少消耗2倍的内存
  • 在ImageLoaderConfiguration中配置图片的内存缓存为memoryCache(new WeakMemoryCache()) 或者不使用内存缓存
  • 在DisplayImageOptions选项中设置.imageScaleType(ImageScaleType.IN_SAMPLE_INT)或者imageScaleType(ImageScaleType.EXACTLY)

通过上面这些,相信大家对Universal-Image-Loader框架的使用已经非常的了解了。我们在使用该框架的时候尽量的使用displayImage()方法去载入图片,loadImage()是将图片对象回调到ImageLoadingListener接口的onLoadingComplete()方法中,须要我们手动去设置到ImageView上面。displayImage()方法中,对ImageView对象使用的是Weak references。方便垃圾回收器回收ImageView对象。假设我们要载入固定大小的图片的时候。使用loadImage()方法须要传递一个ImageSize对象,而displayImage()方法会依据ImageView对象的測量值,或者android:layout_width and android:layout_height设定的值。或者android:maxWidth and/or android:maxHeight设定的值来裁剪图片

今天就给大家分享到这里,有不明确的地方在以下留言,我会尽量为大家解答的。下一篇文章我将继续更深入的分析这个框架,希望大家继续关注。

时间: 2024-10-12 23:13:07

Android 开源框架Universal-Image-Loader全然解析(一)--- 基本介绍及使用的相关文章

开源项目Universal Image Loader for Android 说明文档 (1) 简介

 When developing applications for Android, one often facesthe problem of displaying some graphical content from the Internet. So, youshould provide image loading from the Web in an Android app, their processingand displaying with limited memory aga

Android 开源框架Universal-Image-Loader完全解析(二)--- 图片缓存策略详解

本篇文章继续为大家介绍Universal-Image-Loader这个开源的图片加载框架,介绍的是图片缓存策略方面的,如果大家对这个开源框架的使用还不了解,大家可以看看我之前写的一篇文章Android 开源框架Universal-Image-Loader完全解析(一)--- 基本介绍及使用,我们一般去加载大量的图片的时候,都会做缓存策略,缓存又分为内存缓存和硬盘缓存,我之前也写了几篇异步加载大量图片的文章,使用的内存缓存是LruCache这个类,LRU是Least Recently Used 近

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

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

Android开源框架Universal-Image-Loader解析(一)

来自xiaanming的一篇博客:Android开源框架Universal-Image-Loader解析之基本介绍及使用. 相信大家平时做Android应用的时候,多少会接触到异步加载图片,或者加载大量图片的问题,而加载图片我们常常会遇到许多的问题,比如说图片的错乱,OOM等问题,对于新手来说,这些问题解决起来会比较吃力,所以就有很多的开源图片加载框架应运而生,比较著名的就是Universal-Image-Loader,相信很多朋友都听过或者使用过这个强大的图片加载框架,今天这篇文章就是对这个框

Android开源框架 Android-Universal-Image-Loader

Android开源框架Universal-Image-Loader就像图片加载守护者,为我们提供了丰富的功能特性: (1)多线程加载图像(异步或同步): (2)高度可定制化imageloader配置(线程池.图片下载器.解码器.内存和磁盘缓存.显示图像选项等): (3)每一个显示图像有许多自定义选项(存根图片,缓存开关,解码选项,位图处理和显示等): (4)支持内存和磁盘上的图像缓存(设备的文件系统和SD卡): (5)监听加载过程(包括下载进度): 下来我们详解如何配置使用Universal-I

Android开源框架Afinal第一篇——揭开圣女的面纱

Android开源框架Afinal第一篇——揭开圣女的面纱 分类: Android开源框架哪点事2013-09-02 14:25 260人阅读 评论(0) 收藏 举报 Afinal 这是Afinal在github的地址:https://github.com/yangfuhai/afinal Afinal这个框架主要分4块: 1.FinalDB模块:android中的orm框架,一行代码就可以进行增删改查.支持一对多,多对一等查询. 2.FinalActivity模块:android中的ioc框架

android 开源框架推荐

同事整理的 android 开源框架,个个都堪称经典.32 个赞! 1.volley 项目地址 https://github.com/smanikandan14/Volley-demo (1)  JSON,图像等的异步下载: (2)  网络请求的排序(scheduling) (3)  网络请求的优先级处理 (4)  缓存 (5)  多级别取消请求 (6)  和Activity和生命周期的联动(Activity结束时同时取消所有网络请求) 2.android-async-http  项目地址:ht

Android——开源框架Universal-Image-Loader + Fragment使用+轮播广告

原文地址: Android 开源框架Universal-Image-Loader完全解析(一)--- 基本介绍及使用 Android 开源框架Universal-Image-Loader完全解析(二)--- 图片缓存策略详解 Android Fragment使用(一) 基础篇 温故知新 Android Fragment使用(二) 嵌套Fragments (Nested Fragments) 的使用及常见错误 Android Fragment使用(三) Activity, Fragment, We

六款值得推荐的Android开源框架简介

技术不再多,知道一些常用的.不错的就够了.下面就是最近整理的“性价比”比较高的Android开源框架,应该是相对实用的. 1.volley 项目地址 https://github.com/smanikandan14/Volley-demo JSON,图像等的异步下载: 网络请求的排序(scheduling) 网络请求的优先级处理 缓存 多级别取消请求 和Activity和生命周期的联动(Activity结束时同时取消所有网络请求) 2.android-async-http 项目地址:https:

greenDao android开源框架数据库更新表的问题

最近使用greenDao当android应用升级数据库新增表或者修改表,发现数据被清空的问题 查找资料也没有找到解决方案,最后查看代码发现需要自己修改SQLiteOpenHelper 1.找到greenDao生成的DaoMaster.java文件,里面有SQLiteOpenHelper实现 2.修改DevOpenHelper类里的   public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) 方法 通过old