我们在Android开发难免会碰到图片加载问题,比如最常见的内存溢出OOM,在开发中,现在比较流行的第三方框架比如有以下几个:
1.ImageLoader
2.Picasso
3.Fresco
框架一:ImageLoader
那我们如何使用ImageLoader来加载图片?
1.下载相关jar包 jar包下载地址:http://pan.baidu.com/s/1kUTBe9h(为了方便我放在自己的百度网盘)
2.对jar进行依赖
3.在自定义application中进行配置
先自定义个方法
public static void initImageLoader(Context context) {
personOptions = new DisplayImageOptions.Builder()
.showImageOnFail(R.mipmap.ic_launcher)
.showImageForEmptyUri(R.mipmap.ic_launcher)
.resetViewBeforeLoading(false) // default
.delayBeforeLoading(0)
.cacheInMemory(true) // default
.cacheOnDisk(true) // default
.considerExifParams(true) // default
.imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default
.bitmapConfig(Bitmap.Config.ARGB_8888) // default
.displayer(new SimpleBitmapDisplayer()) // default
.handler(new Handler()) // default
.build();
DisplayImageOptions options = new DisplayImageOptions.Builder()
.showImageOnLoading(R.mipmap.ic_launcher)
// .showImageOnFail(R.drawable.img_fail)
.resetViewBeforeLoading(false) // default
.delayBeforeLoading(0)
.cacheInMemory(true) // default
.cacheOnDisk(true) // default
.considerExifParams(true) // default
.imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default
.bitmapConfig(Bitmap.Config.ARGB_8888) // default
.displayer(new SimpleBitmapDisplayer()) // default
.handler(new Handler()) // default
.build();
// This configuration tuning is custom. You can tune every option, you may tune some of them,
// or you can create default configuration by
// ImageLoaderConfiguration.createDefault(this);
// method.
// File cacheDir = StorageUtils.getCacheDirectory(context);
File picPath=new File(Environment.getExternalStorageDirectory().getPath()+ File.separator+"app_pic"+File.separator+"photos");
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
.memoryCacheExtraOptions(480, 800) // default = device screen dimensions
.diskCacheExtraOptions(480, 800, null)
.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 UnlimitedDiskCache(picPath)) // default
.diskCacheSize(50 * 1024 * 1024)
.diskCacheFileCount(1000)
.diskCacheFileNameGenerator(new HashCodeFileNameGenerator()) // default
.imageDownloader(new BaseImageDownloader(context)) // default
.imageDecoder(new BaseImageDecoder(true)) // default
.defaultDisplayImageOptions(options) // default
.writeDebugLogs()
.build();
// Initialize ImageLoader with configuration.
ImageLoader.getInstance().init(config);
}
然后在application中进行调用
//加载图片设置
initImageLoader(getApplicationContext());
4.加载图片方法
我们可以查看源码中的Imageloader类
其中提供了几种加载图片方式:
1.displayImage()
2.loadImage()
3.loadImageSync()
下面我们查看一下源码:
displayImage的方法:
public void displayImage(String uri, ImageAware imageAware) {
this.displayImage(uri, (ImageAware)imageAware, (DisplayImageOptions)null, (ImageLoadingListener)null, (ImageLoadingProgressListener)null);
}
public void displayImage(String uri, ImageAware imageAware, ImageLoadingListener listener) {
this.displayImage(uri, (ImageAware)imageAware, (DisplayImageOptions)null, listener, (ImageLoadingProgressListener)null);
}
public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options) {
this.displayImage(uri, (ImageAware)imageAware, options, (ImageLoadingListener)null, (ImageLoadingProgressListener)null);
}
public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options, ImageLoadingListener listener) {
this.displayImage(uri, (ImageAware)imageAware, options, listener, (ImageLoadingProgressListener)null);
}
public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options, ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
this.displayImage(uri, imageAware, options, (ImageSize)null, listener, progressListener);
}
public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options, ImageSize targetSize, ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
this.checkConfiguration();
if(imageAware == null) {
throw new IllegalArgumentException("Wrong arguments were passed to displayImage() method (ImageView reference must not be null)");
} else {
if(listener == null) {
listener = this.defaultListener;
}
if(options == null) {
options = this.configuration.defaultDisplayImageOptions;
}
if(TextUtils.isEmpty(uri)) {
this.engine.cancelDisplayTaskFor(imageAware);
listener.onLoadingStarted(uri, imageAware.getWrappedView());
if(options.shouldShowImageForEmptyUri()) {
imageAware.setImageDrawable(options.getImageForEmptyUri(this.configuration.resources));
} else {
imageAware.setImageDrawable((Drawable)null);
}
listener.onLoadingComplete(uri, imageAware.getWrappedView(), (Bitmap)null);
} else {
if(targetSize == null) {
targetSize = ImageSizeUtils.defineTargetSizeForView(imageAware, this.configuration.getMaxImageSize());
}
String memoryCacheKey = MemoryCacheUtils.generateKey(uri, targetSize);
this.engine.prepareDisplayTaskFor(imageAware, memoryCacheKey);
listener.onLoadingStarted(uri, imageAware.getWrappedView());
Bitmap bmp = this.configuration.memoryCache.get(memoryCacheKey);
ImageLoadingInfo imageLoadingInfo;
if(bmp != null && !bmp.isRecycled()) {
L.d("Load image from memory cache [%s]", new Object[]{memoryCacheKey});
if(options.shouldPostProcess()) {
imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey, options, listener, progressListener, this.engine.getLockForUri(uri));
ProcessAndDisplayImageTask displayTask1 = new ProcessAndDisplayImageTask(this.engine, bmp, imageLoadingInfo, defineHandler(options));
if(options.isSyncLoading()) {
displayTask1.run();
} else {
this.engine.submit(displayTask1);
}
} else {
options.getDisplayer().display(bmp, imageAware, LoadedFrom.MEMORY_CACHE);
listener.onLoadingComplete(uri, imageAware.getWrappedView(), bmp);
}
} else {
if(options.shouldShowImageOnLoading()) {
imageAware.setImageDrawable(options.getImageOnLoading(this.configuration.resources));
} else if(options.isResetViewBeforeLoading()) {
imageAware.setImageDrawable((Drawable)null);
}
imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey, options, listener, progressListener, this.engine.getLockForUri(uri));
LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(this.engine, imageLoadingInfo, defineHandler(options));
if(options.isSyncLoading()) {
displayTask.run();
} else {
this.engine.submit(displayTask);
}
}
}
}
}
public void displayImage(String uri, ImageView imageView) {
this.displayImage(uri, (ImageAware)(new ImageViewAware(imageView)), (DisplayImageOptions)null, (ImageLoadingListener)null, (ImageLoadingProgressListener)null);
}
public void displayImage(String uri, ImageView imageView, ImageSize targetImageSize) {
this.displayImage(uri, new ImageViewAware(imageView), (DisplayImageOptions)null, targetImageSize, (ImageLoadingListener)null, (ImageLoadingProgressListener)null);
}
public void displayImage(String uri, ImageView imageView, DisplayImageOptions options) {
this.displayImage(uri, (ImageAware)(new ImageViewAware(imageView)), options, (ImageLoadingListener)null, (ImageLoadingProgressListener)null);
}
public void displayImage(String uri, ImageView imageView, ImageLoadingListener listener) {
this.displayImage(uri, (ImageAware)(new ImageViewAware(imageView)), (DisplayImageOptions)null, listener, (ImageLoadingProgressListener)null);
}
public void displayImage(String uri, ImageView imageView, DisplayImageOptions options, ImageLoadingListener listener) {
this.displayImage(uri, (ImageView)imageView, options, listener, (ImageLoadingProgressListener)null);
}
public void displayImage(String uri, ImageView imageView, DisplayImageOptions options, ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
this.displayImage(uri, (ImageAware)(new ImageViewAware(imageView)), options, listener, progressListener);
}
loadImage的方法:
public void loadImage(String uri, ImageLoadingListener listener) {
this.loadImage(uri, (ImageSize)null, (DisplayImageOptions)null, listener, (ImageLoadingProgressListener)null);
}
public void loadImage(String uri, ImageSize targetImageSize, ImageLoadingListener listener) {
this.loadImage(uri, targetImageSize, (DisplayImageOptions)null, listener, (ImageLoadingProgressListener)null);
}
public void loadImage(String uri, DisplayImageOptions options, ImageLoadingListener listener) {
this.loadImage(uri, (ImageSize)null, options, listener, (ImageLoadingProgressListener)null);
}
public void loadImage(String uri, ImageSize targetImageSize, DisplayImageOptions options, ImageLoadingListener listener) {
this.loadImage(uri, targetImageSize, options, listener, (ImageLoadingProgressListener)null);
}
public void loadImage(String uri, ImageSize targetImageSize, DisplayImageOptions options, ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
this.checkConfiguration();
if(targetImageSize == null) {
targetImageSize = this.configuration.getMaxImageSize();
}
if(options == null) {
options = this.configuration.defaultDisplayImageOptions;
}
NonViewAware imageAware = new NonViewAware(uri, targetImageSize, ViewScaleType.CROP);
this.displayImage(uri, (ImageAware)imageAware, options, listener, progressListener);
}
loadImageSync的方法:
我们可以根据自己的需求去封装类,然后调用,方便后期程序的开发,减少代码的冗余。public Bitmap loadImageSync(String uri) { return this.loadImageSync(uri, (ImageSize)null, (DisplayImageOptions)null); } public Bitmap loadImageSync(String uri, DisplayImageOptions options) { return this.loadImageSync(uri, (ImageSize)null, options); } public Bitmap loadImageSync(String uri, ImageSize targetImageSize) { return this.loadImageSync(uri, targetImageSize, (DisplayImageOptions)null); } public Bitmap loadImageSync(String uri, ImageSize targetImageSize, DisplayImageOptions options) { if(options == null) { options = this.configuration.defaultDisplayImageOptions; } options = (new Builder()).cloneFrom(options).syncLoading(true).build(); ImageLoader.SyncImageLoadingListener listener = new ImageLoader.SyncImageLoadingListener(); this.loadImage(uri, targetImageSize, options, listener); return listener.getLoadedBitmap(); }
关键类:
ImageLoader
DisplayImageOptions
ImageLoaderConfiguration
框架二:Picasso
我们如何使用Picasso加载图片?
1.在app中的grade中进行依赖
compile 'com.squareup.picasso:picasso:2.5.2'
2.简单的使用
Picasso.with(getBaseContext()).load(R.mipmap.a).resize(100,100).centerCrop().into(img);
3.自定义类处理图片加载,然后在其他类中进行调用 起到控制的作用
<span style="font-size:18px;">package com.example.boom.picproject.core;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Environment;
import android.widget.ImageView;
import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
public class PicassoHelper {
public static void LoadImage(Context _context,String url,String fileName,final ImageView target) {
LoadImage(_context,url,fileName,target,null);
}
public static void LoadImage(Context _context, String url, final String fileName , final ImageView target, final Callback callback) {
url = url.replaceAll(" ", "%20");
if(fileName != null && !fileName.equals(""))
{
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),fileName);
if (file.exists()) {
Bitmap bm = BitmapFactory.decodeFile(file.getPath());
target.setImageBitmap(bm);
if(callback != null) callback.onSuccess();
return ;
}
}
final ArrayList<String> urlList = new ArrayList<>();
final Callback localCallback = new Callback() {
@Override
public void onSuccess() {
if(callback != null) callback.onSuccess();
else {
if (fileName != null && !fileName.equals("")) {
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), fileName);
if (!file.exists()) {
FileOutputStream out = null;
try {
Bitmap bitmap = ((BitmapDrawable) target.getDrawable()).getBitmap();
out = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
}
@Override
public void onError() {
if(callback != null) callback.onError();
}
};
urlList.add(url);
Picasso picasso = new Picasso.Builder(_context).listener(new Picasso.Listener() {
@Override
public void onImageLoadFailed(Picasso picasso, Uri uri, Exception exception) {
boolean needLoadLocalFile = true;
String message = exception.getMessage();
if (message != null && message.contains("302")) {
String tempUrl = uri.toString();
if(tempUrl.startsWith("http://"))
{
tempUrl = tempUrl.replace("http://","https://");
}else{
tempUrl = tempUrl.replace("https://","http://");
}
if(!urlList.contains(tempUrl))
{
urlList.add(tempUrl);
needLoadLocalFile = false;
picasso.load(tempUrl).into(target,localCallback);
}
}
if(needLoadLocalFile){
if(fileName != null && !fileName.equals(""))
{
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),fileName);
if (file.exists()) {
Bitmap bm = BitmapFactory.decodeFile(file.getPath());
target.setImageBitmap(bm);
}
}
}
}
}).build();
picasso.load(url).into(target,localCallback);
}
public static void LoadImage(Context _context,String url,final ImageView target) {
LoadImage(_context,url,"",target,null);
}
public static void LoadImage(Context _context,String url,final ImageView target,final Callback callback) {
LoadImage(_context,url,"",target,callback);
}
}<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span></span>
查看源码加载图片的方法:
Picasso类中的方法(普通)
/**
* Start an image request using the specified URI.
* <p>
* Passing {@code null} as a {@code uri} will not trigger any request but will set a placeholder,
* if one is specified.
*
* @see #load(File)
* @see #load(String)
* @see #load(int)
*/
public RequestCreator load(Uri uri) {
return new RequestCreator(this, uri, 0);
}
/**
* Start an image request using the specified path. This is a convenience method for calling
* {@link #load(Uri)}.
* <p>
* This path may be a remote URL, file resource (prefixed with {@code file:}), content resource
* (prefixed with {@code content:}), or android resource (prefixed with {@code
* android.resource:}.
* <p>
* Passing {@code null} as a {@code path} will not trigger any request but will set a
* placeholder, if one is specified.
*
* @see #load(Uri)
* @see #load(File)
* @see #load(int)
* @throws IllegalArgumentException if {@code path} is empty or blank string.
*/
public RequestCreator load(String path) {
if (path == null) {
return new RequestCreator(this, null, 0);
}
if (path.trim().length() == 0) {
throw new IllegalArgumentException("Path must not be empty.");
}
return load(Uri.parse(path));
}
/**
* Start an image request using the specified image file. This is a convenience method for
* calling {@link #load(Uri)}.
* <p>
* Passing {@code null} as a {@code file} will not trigger any request but will set a
* placeholder, if one is specified.
* <p>
* Equivalent to calling {@link #load(Uri) load(Uri.fromFile(file))}.
*
* @see #load(Uri)
* @see #load(String)
* @see #load(int)
*/
public RequestCreator load(File file) {
if (file == null) {
return new RequestCreator(this, null, 0);
}
return load(Uri.fromFile(file));
}
/**
* Start an image request using the specified drawable resource ID.
*
* @see #load(Uri)
* @see #load(String)
* @see #load(File)
*/
public RequestCreator load(int resourceId) {
if (resourceId == 0) {
throw new IllegalArgumentException("Resource ID must not be zero.");
}
return new RequestCreator(this, null, resourceId);
}
用建造者模式
/** Start building a new {@link Picasso} instance. */
public Builder(Context context) {
if (context == null) {
throw new IllegalArgumentException("Context must not be null.");
}
this.context = context.getApplicationContext();
}
/**
* Specify the default {@link Bitmap.Config} used when decoding images. This can be overridden
* on a per-request basis using {@link RequestCreator#config(Bitmap.Config) config(..)}.
*/
public Builder defaultBitmapConfig(Bitmap.Config bitmapConfig) {
if (bitmapConfig == null) {
throw new IllegalArgumentException("Bitmap config must not be null.");
}
this.defaultBitmapConfig = bitmapConfig;
return this;
}
框架三:Fresco
这是我最近在看的一个第三方sdk,感觉很好,并且很强大,这里就简单的说说使用,主要还是参考他的网址介绍:http://www.fresco-cn.org/docs/using-drawees-code.html,上面介绍如何使用还是很详细的。
1.app中grade如何配置
<span style="font-size:18px;"> compile 'com.facebook.fresco:fresco:0.12.0'</span>
<span style="font-size:18px;"> // 在 API < 14 上的机器支持 WebP 时,需要添加
compile 'com.facebook.fresco:animated-base-support:0.12.0'
// 支持 GIF 动图,需要添加
compile 'com.facebook.fresco:animated-gif:0.12.0'
// 支持 WebP (静态图+动图),需要添加
compile 'com.facebook.fresco:animated-webp:0.12.0'
compile 'com.facebook.fresco:webpsupport:0.12.0'
// 仅支持 WebP 静态图,需要添加
compile 'com.facebook.fresco:webpsupport:0.12.0'</span>
在自定义application中初始化
<span style="font-size:18px;">Fresco.initialize(this);</span>
主要控件
<span style="font-size:18px;"><com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/my_image_view"
android:layout_width="130dp"
android:layout_height="130dp"
fresco:placeholderImage="@drawable/my_drawable"
/></span>
代码实现:
<span style="font-size:18px;">Uri uri = Uri.parse("https://raw.githubusercontent.com/facebook/fresco/gh-pages/static/logo.png");
SimpleDraweeView draweeView = (SimpleDraweeView) findViewById(R.id.my_image_view);
draweeView.setImageURI(uri);</span>
我们在利用第三方sdk的时候,这是其中解决OOM问题之一,我们也可以自己通过对图片的大小进行压缩或对图片的格式进行更改,比如把png图片转换成jpg图片。对处理离线缓存有很大的用处。
最后我们记得还要加上User权限
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />