Android图片加载与缓存开源框架总结七部曲:Glide Picasso ImageLoader Fresco ASimpleCache等

Posted 冰糖葫芦三剑客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android图片加载与缓存开源框架总结七部曲:Glide Picasso ImageLoader Fresco ASimpleCache等相关的知识,希望对你有一定的参考价值。

 

                                                       android图片加载与缓存开源框架总结

 

 

  1)    Picasso      点击下面红色字体进入详解: picasso-强大的Android图片下载缓存库   2)    Glide         点击下面红色字体进入详解: Google推荐的图片加载库Glide介绍   3)    Fresco       点击下面红色字体进入详解: Fresco使用教程 4)    ImageLoader 点击下面红色字体进入详解: Android UI-开源框架ImageLoader的完美例子

 

 

 

      ImageLoader可以支持图片下载的过程监听,Picasso和Glide都是非常优秀的,而且使用起来非常容易上手,我们站在用户的需求上考虑,若用户要求更完美的展示图片的细节,那么非Picasso莫属,若更注重于顺滑的图片滑动体验Glide更加适合。

 

                    ImageLoader其实也不难,下面来看看代码:

下载地址:

http://download.csdn.net/detail/wwj_748/5975847

http://download.csdn.net/detail/wwj_748/5975847

要使用ImageLoader就要到这里下载jar包:

 

https://github.com/nostra13/Android-Universal-Image-Loader

 

1.功能概要

 Android-Universal-Image-Loader是一个开源的UI组件程序,该项目的目的是提供一个可重复使用的仪器为异步图像加载,缓存和显示。

(1).使用多线程加载图片
(2).灵活配置ImageLoader的基本参数,包括线程数、缓存方式、图片显示选项等;
(3).图片异步加载缓存机制,包括内存缓存及SDCard缓存;
(4).采用监听器监听图片加载过程及相应事件的处理;
(5).配置加载的图片显示选项,比如图片的圆角处理及渐变动画。

2.简单实现

ImageLoader采用单例设计模式,ImageLoader imageLoader = ImageLoader.getInstance();得到该对象,每个ImageLoader采用单例设计模式,ImageLoader必须调用init()方法完成初始化。

  1. //  1.完成ImageLoaderConfiguration的配置  
  2. ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(this)  
  3.     .memoryCacheExtraOptions(480, 800)          // default = device screen dimensions  
  4.     .discCacheExtraOptions(480, 800, CompressFormat.JPEG, 75, null)  
  5.     .taskExecutor(...)  
  6.     .taskExecutorForCachedImages(...)  
  7.     .threadPoolSize(3)                          // default  
  8.     .threadPriority(Thread.NORM_PRIORITY - 1)   // default  
  9.     .tasksProcessingOrder(QueueProcessingType.FIFO) // default  
  10.     .denyCacheImageMultipleSizesInMemory()  
  11.     .memoryCache(new LruMemoryCache(2 * 1024 * 1024))  
  12.     .memoryCacheSize(2 * 1024 * 1024)  
  13.     .memoryCacheSizePercentage(13)              // default  
  14.     .discCache(new UnlimitedDiscCache(cacheDir))// default  
  15.     .discCacheSize(50 * 1024 * 1024)        // 缓冲大小  
  16.     .discCacheFileCount(100)                // 缓冲文件数目  
  17.     .discCacheFileNameGenerator(new HashCodeFileNameGenerator()) // default  
  18.     .imageDownloader(new BaseImageDownloader(context)) // default  
  19.     .imageDecoder(new BaseImageDecoder()) // default  
  20.     .defaultDisplayImageOptions(DisplayImageOptions.createSimple()) // default  
  21.     .writeDebugLogs()  
  22.     .build();  
  23.   
  24. //  2.单例ImageLoader类的初始化  
  25. ImageLoader imageLoader = ImageLoader.getInstance();  
  26. imageLoader.init(config);  
  27.   
  28. //  3.DisplayImageOptions实例对象的配置  
  29. //      以下的设置再调用displayImage()有效,使用loadImage()无效  
  30. DisplayImageOptions options = new DisplayImageOptions.Builder()  
  31.     .showStubImage(R.drawable.ic_stub)          // image在加载过程中,显示的图片  
  32.     .showImageForEmptyUri(R.drawable.ic_empty)  // empty URI时显示的图片  
  33.     .showImageOnFail(R.drawable.ic_error)       // 不是图片文件 显示图片  
  34.     .resetViewBeforeLoading(false)  // default  
  35.     .delayBeforeLoading(1000)  
  36.     .cacheInMemory(false)           // default 不缓存至内存  
  37.     .cacheOnDisc(false)             // default 不缓存至手机SDCard  
  38.     .preProcessor(...)  
  39.     .postProcessor(...)  
  40.     .extraForDownloader(...)  
  41.     .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2)// default  
  42.     .bitmapConfig(Bitmap.Config.ARGB_8888)              // default  
  43.     .decodingOptions(...)  
  44.     .displayer(new SimpleBitmapDisplayer()) // default 可以设置动画,比如圆角或者渐变  
  45.     .handler(new Handler())                             // default  
  46.     .build();  
  47.       
  48. //  4图片加载  
  49. //  4.1 调用displayImage  
  50. imageLoader.displayImage(  
  51.     uri,        /* 
  52.                     String imageUri = "http://site.com/image.png";      // from Web 
  53.                     String imageUri = "file:///mnt/sdcard/image.png";   // from SD card 
  54.                     String imageUri = "content://media/external/audio/albumart/13"; // from content provider 
  55.                     String imageUri = "assets://image.png";             // from assets 
  56.                     */  
  57.     imageView,      // 对应的imageView控件  
  58.     options);       // 与之对应的image显示方式选项  
  59.   
  60. //  4.2 调用loadImage  
  61. //      对于部分DisplayImageOptions对象的设置不起作用  
  62. imageLoader.loadImage(  
  63.         uri,   
  64.         options,   
  65.         new MyImageListener()); //ImageLoadingListener  
  66. class MyImageListener extends SimpleImageLoadingListener  
  67.   
  68.     @Override  
  69.     public void onLoadingStarted(String imageUri, View view)   
  70.         imageView.setImageResource(R.drawable.loading);  
  71.         super.onLoadingStarted(imageUri, view);  
  72.       
  73.   
  74.     @Override  
  75.     public void onLoadingFailed(String imageUri, View view,  
  76.             FailReason failReason)   
  77.         imageView.setImageResource(R.drawable.no_pic);  
  78.         super.onLoadingFailed(imageUri, view, failReason);  
  79.       
  80.   
  81.     @Override  
  82.     public void onLoadingComplete(String imageUri, View view,  
  83.             Bitmap loadedImage)   
  84.         imageView.setImageBitmap(loadedImage);  
  85.         super.onLoadingComplete(imageUri, view, loadedImage);  
  86.       
  87.   
  88.     @Override  
  89.     public void onLoadingCancelled(String imageUri, View view)   
  90.         imageView.setImageResource(R.drawable.cancel);  
  91.         super.onLoadingCancelled(imageUri, view);  
  92.       
  93.       
  94.   

3.支持的Uri

  1. String imageUri = "http://site.com/image.png";      // from Web  
  2. String imageUri = "file:///mnt/sdcard/image.png";   // from SD card  
  3. String imageUri = "content://media/external/audio/albumart/13"; // from content provider  
  4. String imageUri = "assets://image.png";             // from assets  
  5. String imageUri = "drawable://" + R.drawable.image; // from drawables (only images, non-9patch)  

 

加载drawables下图片,可以通过ImageView.setImageResource(...) 而不是通过上面的ImageLoader.

4.缓冲至手机

默认不能保存缓存,必须通过下面的方式指定

  1. DisplayImageOptions options = new DisplayImageOptions.Builder()  
  2.         ...  
  3.         .cacheInMemory(true)  
  4.         .cacheOnDisc(true)  
  5.         ...  
  6.         .build();  
  7. ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())  
  8.         ...  
  9.         .defaultDisplayImageOptions(options)  
  10.         ...  
  11.         .build();  
  12. ImageLoader.getInstance().init(config); // Do it on Application start  
  13.   
  14. ImageLoader.getInstance().displayImage(imageUrl, imageView);    /* 
  15.                                             默认为defaultDisplayImageOptions设定的options对象,此处不用指定options对象 */  

或者通过下面这种方式

  1. DisplayImageOptions options = new DisplayImageOptions.Builder()  
  2.         ...  
  3.         .cacheInMemory(true)  
  4.         .cacheOnDisc(true)  
  5.         ...  
  6.         .build();  
  7. ImageLoader.getInstance().displayImage(imageUrl, imageView, options); //此处指定options对象  

由于缓存需要在外设中写入数据,故需要添加下面的权限

  1. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>  

5.OutOfMemoryError

如果OutOfMemoryError错误很常见,可以通过下面的方式设置
(1).减少configuration中线程池的线程数目(.threadPoolSize(...)) 推荐为1 - 5
(2).display options通过.bitmapConfig(Bitmap.Config.RGB_565)设置. Bitmaps in RGB_565 consume 2 times less memory than in ARGB_8888.
(3).使用configuration的memoryCache(new WeakMemoryCache())方法 或者不调用.cacheInMemory()方法
(4).display options通过.imageScaleType(ImageScaleType.IN_SAMPLE_INT) 或者 .imageScaleType(ImageScaleType.EXACTLY)方法
(4).避免使用RoundedBitmapDisplayer,它创建了一个新的ARGB_8888 Bitmap对象

6.内存缓存管理

通过imageLoaderConfiguration.memoryCache([new LruMemoryCache(1)]))对手机内存缓存进行管理

LruMemoryCache

API >= 9默认.it is moved to the head of a queue.

FreqLimitedMemoryCache

当超过缓存大小后,删除最近频繁使用的bitmap

LRULimitedMemoryCache

API < 9 默认.当超过缓存大小后,删除最近使用的bitmap

FIFOLimitedMemoryCache

FIFO rule is used for deletion when cache size limit is exceeded

LargestLimitedMemoryCache

The largest bitmap is deleted when cache size limit is exceeded

WeakMemoryCache

Unlimited cache

7.SDcard缓存管理

通过imageLoaderConfiguration.discCache([new TotalSizeLimitedDiscCache()]))对SD卡缓存进行管理

UnlimitedDiscCache

default The fastest cache, doesn't limit cache size

TotalSizeLimitedDiscCache

Cache limited by total cache size. If cache size exceeds specified limit then file with themost oldest lastusage date will be deleted

FileCountLimitedDiscCache

Cache limited by file count. If file count in cache directory exceeds specified limit then file with the most oldest last usage date will be deleted.

LimitedAgeDiscCache

Size-unlimited cache with limited files' lifetime. If age of cached file exceeds defined limit then it will be deleted from cache.

UnlimitedDiscCache is 30%-faster than other limited disc cache implementations.

 

 

 

?

 

Glide是谷歌推荐使用的加载图片的框架,它相对于其他的框架有更多的有点,说到Glide我们不得不谈谈Picasso,为什么呢?这是因为Picasso的使用与Glide的使用上非常的相似,但是细细看,有明显不同,首先我们看下Picasso与Glide的基本用法?


Picasso:            


   Picasso.with(this)
                 .load(url)//加载图片
                 .placeholder(R.mipmap.ic_launcher)//正在加载时的图片
                 .error(R.mipmap.ic_launcher)//加载错误是的图片
                 .into(glide_image2);
Glide:


  Glide.with(this)
                 .load(url)//加载图片
               .placeholder(R.mipmap.ic_launcher)//正在加载时的图片
                 .error(R.mipmap.ic_launcher)//加载错误是的图片
                 .into(glide_image);
1、看到没有,是不是一样呢,基本上它们的用法一直,但是我们在使用Glide时需要注意,Glide.with(this),我们在传入的时候,我建议传入Actitiy,Fragment对应得context,而不是全局的context,为什么呢,这是因为这样我们可以让Gilde加载图片与我们的Activity,Fragment的生命周期一直,创建时去加载,销毁时停止加载,


2、Glide的加载速度比Picasso的加载速度要快,但是消耗的内存要比Picasso的内存高,为什么呢这是因为Gilde他是根据你传入的尺寸进行缓存,如果俩个地方需要      全尺寸缓存,另一个地方按照比例缓存,那么Glide需要缓存俩次,而Picsso是全尺寸的缓存,每当重新加载时,需要重新绘制


   /**
       * Glide的全尺寸缓存
       */
      public void GlideImage3(String url)
          Glide.with(this)
                  .load(url)//加载图片
                  .placeholder(R.mipmap.ic_launcher)//正在加载时的图片
                  .error(R.mipmap.ic_launcher)//加载错误是的图片
                  .diskCacheStrategy(DiskCacheStrategy.ALL)
                 .into(glide_image);
     
 

3,Picasso加载的bitmap格式ARGB_8888而Glide所加载的bitmap格式ARGB_565当然我们可以通过实现GlideMenu来实现

  /**
   * 更改Glide的bitmap的格式为ARGB_8888
   * Created by joe.xiang on 2016/6/9.
   */
 public class GlideConfigration implements GlideModule
  
  
      @Override
      public void applyOptions(Context context, GlideBuilder builder)
         builder.setDecodeFormat(DecodeFormat.PREFER_ARGB_8888);
     
 
     @Override
     public void registerComponents(Context context, Glide glide)
 
     
 

 

4、Glide的setTag方法不同之处?


   我们可以通过在我们的values下建立一个ids的xml


<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="image_tag" type="id"/>
</resources>
通过Image.setTag(R.id.image_tag,url)的形式来进行设置

5、Glide如何设置圆形图片


    对于如何制作圆形的方法,有很多可以通过自定义ImageView,当然Glide也给我们提供了很多的方法来时圆角图片。一般有一下方法


    1、自定一个Transform 继承 BitmapTransformation




  /**
   * Created by joe.xiang on 2016/6/9.
   */
  public  class CircleTransform extends BitmapTransformation
  
      public CircleTransform(Context context)
         super(context);
     
 
    @Override protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight)
         return circleCrop(pool, toTransform);
     
 
     private static Bitmap circleCrop(BitmapPool pool, Bitmap source)
         if (source == null) return null;
         int size = Math.min(source.getWidth(), source.getHeight());
         int x = (source.getWidth() - size) / 2;
         int y = (source.getHeight() - size) / 2;
 
         // TODO this could be acquired from the pool too
         Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);
         Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888);
         if (result == null)
             result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
         
         Canvas canvas = new Canvas(result);
         Paint paint = new Paint();
         paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
         paint.setAntiAlias(true);
         float r = size / 2f;
         canvas.drawCircle(r, r, r, paint);
        return result;
     
 
     @Override public String getId()
         return getClass().getName();
     
 




    /**
       * 通过Glide的TransForMation 自定义圆形图片的bitmap
       */
      public void RoundImage(String url)
          Glide.with(this)
                  .load(url)
                  .asBitmap()
                  .transform(new CircleTransform(this))
                  .into(glide_image5);
     


 2、我们可以通过BitmapImageVieTarget,来得到一个带圆角的RoundBitmapDrawable;


   /**
       * 通过RoundBitmapDrawable
       */
      public void RoundImage2(String url)
          Glide.with(this)
                  .load(url)
                  .asBitmap()
                  .into(new BitmapImageViewTarget(glide_image6)
                     @Override
                     protected void setResource(Bitmap resource)
                        RoundedBitmapDrawable RoundedBitmapDrawable = RoundedBitmapDrawableFactory.create(Glide_1.this.getResources(), resource);
                        RoundedBitmapDrawable.setCircular(true);
                         glide_image6.setImageDrawable(RoundedBitmapDrawable);
                   
               );


3、我们可以通过自定义RoundedCornerLayout 继承RelavityLayout来实现圆角图片效果


  **
   * Created by joe.xiang on 2016/6/9.
   */
  public class RoundedCornerLayout  extends RelativeLayout
      private Bitmap maskBitmap;
      private Paint paint;
      private float cornerRadius;
  
     public RoundedCornerLayout(Context context)
         super(context);
         init(context, null, 0);
     
     public RoundedCornerLayout(Context context, AttributeSet attrs)
         super(context, attrs);
         init(context, attrs, 0);
   
 
     public RoundedCornerLayout(Context context, AttributeSet attrs, int defStyle)
         super(context, attrs, defStyle);
         init(context, attrs, defStyle);
     
 
    private void init(Context context, AttributeSet attrs, int defStyle)
         paint = new Paint(Paint.ANTI_ALIAS_FLAG);
         setWillNotDraw(false);
   


     @Override
     public void draw(Canvas canvas)
         super.draw(canvas);
 
         if (maskBitmap == null)
            // This corner radius assumes the image width == height and you want it to be circular
             // Otherwise, customize the radius as needed
             cornerRadius = canvas.getWidth() / 2;
             maskBitmap = createMask(canvas.getWidth(), canvas.getHeight());
         
 
         canvas.drawBitmap(maskBitmap, 0f, 0f, paint);
     


     private Bitmap createMask(int width, int height)
        Bitmap mask = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
         Canvas canvas = new Canvas(mask);
 
         Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
         paint.setColor(Color.WHITE); // TODO set your background color as needed
 
         canvas.drawRect(0, 0, width, height, paint);
 
         paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
         canvas.drawRoundRect(new RectF(0, 0, width, height), cornerRadius, cornerRadius, paint);
         return mask;
     
 




    <huanxin.exmaple.com.android_glidedemo.RoundedCornerLayout
                     android:layout_width="200dp"
                     android:layout_height="200dp">
                        <ImageView
                             android:id="@+id/glide_image7"
                             android:layout_width="200dp"
                            android:layout_height="200dp"
                            android:scaleType="centerCrop"
                            />
  </huanxin.exmaple.com.android_glidedemo.RoundedCornerLayout>


使用上跟一般使用没什么区别。。。。。


4 、当然我们亦可以使用开源的圆角图片的自定义控件?




   Glide.with(this).load(url).into(new SimpleTarget<GlideDrawable>()
              @Override
              public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> glideAnimation)
                  //使用自定义的圆角图片
             
          );


对于Glide加载图片还有很多可以去研究的地方,它还可以加载gif的动态图,不过这个方法要谨慎使用,因为这个非常耗内存,对于Glide的使用花了一个下午对于他的一些基本使用就总结导致,过段时间深入研究后在总结了、一下附上加载的图片效果图。

 

                                                                                 Android Glide

 

 

Android Glide是一个开源的图片加载和缓存处理的第三方框架。和Android的Picasso库类似,个人感觉比Android Picasso好用。Android Glide使自身内部已经实现了缓存策略,使得开发者摆脱Android图片加载的琐碎事务,专注逻辑业务的代码。Android Glide使用便利,短短几行简单明晰的代码,即可完成大多数图片从网络(或者本地)加载、显示的功能需求。

使用Android Glide,需要先下载Android Glide的库,Android Glide在github上的项目主页:

https://github.com/bumptech/glide 。

实际的项目使用只需要到Glide的releases页面把jar包下载后导入到本地的libs里面即可直接使用。Glide的releases的页面地址:https://github.com/bumptech/glide/releases ,在此页面找到最新的jar包,下载后放到自己项目的libs中,比如glide 3.6.0库的jar包下载地址:https://github.com/bumptech/glide/releases/download/v3.6.0/glide-3.6.0.jar


接下来是在自己的项目中具体使用,现在给出一个具体的使用例子加以简单说明(通过网络加载图片然后在ImageView中显示出来):

MainActivity.java

 下载地址:

http://download.csdn.net/detail/shenggaofei/9613805

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 import com.bumptech.glide.Glide;   import android.support.v7.app.ActionBarActivity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.ListView; import android.app.Activity; import android.content.Context; import android.os.Bundle;   public class MainActivity extends ActionBarActivity        private Activity mActivity;      // 将从此URL加载网络图片。      private String img_url = "https://avatar.csdn.net/9/7/A/1_zhangphil.jpg" ;        @Override      protected void onCreate(Bundle savedInstanceState)          super .onCreate(savedInstanceState);          mActivity = this ;            setContentView(R.layout.activity_main);            ListView lv = (ListView) findViewById(R.id.listView);          lv.setAdapter( new MyAdapter( this , R.layout.item));             private class MyAdapter extends ArrayAdapter            private int resource;            public MyAdapter(Context context, int resource)              super (context, resource);              this .resource = resource;                     @Override          public View getView( int position, View convertView, ViewGroup parent)              if (convertView == null )                  convertView = LayoutInflater.from(mActivity).inflate(resource,                          null );                             ImageView iv = (ImageView) convertView.findViewById(R.id.imageView);                Glide.with(mActivity).load(img_url).centerCrop()              /*               * 缺省的占位图片,一般可以设置成一个加载中的进度GIF图               */              .placeholder(R.drawable.loading).crossFade().into(iv);                return convertView;                     @Override          public int getCount()              // 假设加载的数据量很大              return 10000 ;              

 

 

 

MainActivity.java需要的两个布局文件:

activity_main.xml

 

?
1 2 3 4 5 6 <linearlayout android:layout_height= "match_parent" android:layout_width= "match_parent" android:orientation= "vertical" xmlns:android= "http://schemas.android.com/apk/res/android" >        <listview android:id= "@+id/listView" android:layout_height= "wrap_content" android:layout_width= "match_parent" >      </listview>   </linearlayout>

 

 

 

 

item.xml

 

?
1 2 3 4 5 6 <!--?xml version= "1.0" encoding= "utf-8" ?--> <linearlayout android:layout_height= "match_parent" android:layout_width= "match_parent" android:orientation= "vertical" xmlns:android= "http://schemas.android.com/apk/res/android" >        <imageview android:id= "@+id/imageView" android:layout_height= "wrap_content" android:layout_width= "wrap_content" >   </imageview></linearlayout>  

                                                                     

 

                                                               

Android Picasso加载网络图片等比例缩放

 

下载地址:

http://download.csdn.net/my

在做Android图片加载的时候,由于手机屏幕受限,很多大图加载过来的时候,我们要求等比例缩放,比如按照固定的宽度,等比例缩放高度,使得图片的尺寸比例得到相应的缩放,但图片没有变形。显然按照android:scaleType不能实现,因为会有很多限制,所以必须要自己写算法。 
之前也写过一篇文章Android根据屏幕宽度缩放图片,但这是缩放的本地图片,网络图片该如何办呢?

通过Picasso来缩放 
其实picasso提供了这样的方法。具体是显示Transformation 的transform方法。 
1、先获取网络或本地图片的宽高 
2、获取需要的目标宽 
3、按比例得到目标的高度 
4、按照目标的宽高创建新图

<code class="hljs mel has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span style="font-size:18px;">Transformation transformation = new Transformation() 

        <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">@Override</span>
        public Bitmap transform(Bitmap <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">source</span>) 

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> targetWidth = mImg.getWidth();
        LogCat.i(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"source.getHeight()="</span>+<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">source</span>.getHeight()+<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">",source.getWidth()="</span>+<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">source</span>.getWidth()+<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">",targetWidth="</span>+targetWidth);

        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">source</span>.getWidth()==<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">source</span>;
        

        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//如果图片小于设置的宽度,则返回原图</span>
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span>(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">source</span>.getWidth()<targetWidth)
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">source</span>;
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span>
            <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//如果图片大小大于等于设置的宽度,则按照设置的宽度比例来缩放</span>
            double aspectRatio = (double) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">source</span>.getHeight() / (double) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">source</span>.getWidth();
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> targetHeight = (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span>) (targetWidth * aspectRatio);
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (targetHeight != <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> && targetWidth != <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>) 
                Bitmap result = Bitmap.createScaledBitmap(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">source</span>, targetWidth, targetHeight, false);
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (result != <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">source</span>) 
                    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// Same bitmap is returned if sizes are the same</span>
                    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">source</span>.recycle();
                
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> result;
             <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> 
                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">source</span>;
            
        

    

        <span class="hljs-variable" style="color: rgb(102, 0, 102); box-sizing: border-box;">@Override</span>
        public String key() 
            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"transformation"</span> + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" desiredWidth"</span>;
        
    ;</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">1</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">2</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">3</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">4</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">5</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">6</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">7</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">8</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">9</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">10</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">11</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">12</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">13</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">14</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">15</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">16</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">17</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">18</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">19</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">20</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">21</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">22</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">23</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">24</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">25</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">26</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">27</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">28</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">29</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">30</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">31</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">32</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">33</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">34</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">35</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">36</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">37</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">38</span></li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">1</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">2</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">3</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">4</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">5</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">6</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">7</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">8</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">9</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">10</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">11</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">12</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">13</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">14</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">15</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">16</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">17</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">18</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">19</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">20</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">21</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">22</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">23</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">24</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">25</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">26</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">27</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">28</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">29</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">30</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">31</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">32</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">33</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">34</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">35</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">36</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">37</span></li><li style="box-sizing: border-box; padding: 0px 5px;"><span style="font-size:18px;">38</span></li></ul>

以上是关于Android图片加载与缓存开源框架总结七部曲:Glide Picasso ImageLoader Fresco ASimpleCache等的主要内容,如果未能解决你的问题,请参考以下文章

25类Android常用开源框架

Android开发常用开源框架:图片处理

Android开发常用开源框架:图片处理

Android开发常用开源框架:图片处理

Android_开源框架_AndroidUniversalImageLoader网络图片加载

Android 开源框架 ( 九 ) 图片加载框架---ImageLoader