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

 

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

 

 

  1)    Picasso      点击下面红色字体进入详解:
  2)    Glide         点击下面红色字体进入详解:
  3)    Fresco       点击下面红色字体进入详解:
4)    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>

之后在Picasso设置transform

<code class="hljs avrasm 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;">            Picasso<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.with</span>(mContext)
                    <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.load</span>(imageUrl)
                    <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.placeholder</span>(R<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.mipmap</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.zhanwei</span>)
                    <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.error</span>(R<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.mipmap</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.zhanwei</span>)
                    <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.transform</span>(transformation)
                    <span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.into</span>(viewHolder<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.mImageView</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</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></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></ul>

参考文献: 
http://stackoverflow.com/questions/21889735/resize-image-to-full-width-and-variable-height-with-picasso 
http://blog.csdn.net/larryl2003/article/details/6919513

                                  

                                                              

                                          ASimpleCache缓存框架的使用

 简述

简述为ASimpleCache官网( 点击打开链接)对其介绍,ASimpleCache 是一个为android制定的 轻量级的 开源缓存框架。轻量到只有一个java文件(由十几个类精简而来)。

0.1ASimpleCache可以缓存什么

普通的字符串、JsonObject、JsonArray、Bitmap、Drawable、序列化的java对象,和 byte数据。

0.2ASimpleCache有什么特色

(1)轻:轻到只有一个JAVA文件;
(2)可配置:可以配置缓存路径,缓存大小,缓存数量等;
(3)可以设置缓存超时时间,缓存超时自动失效,并被删除;
(4)支持多进程。

0.3ASimpleCache在Android中的使用场景

(1)替换SharePreference当做配置文件;
(2)可以缓存网络请求数据,可以作为app数据(字符串、JsonObject、JsonArray、Bitmap、Drawable、序列化的java对象,和 byte数据)的缓存工具;
(3)可以作为预加载数据的缓存库;

1ASimpleCache的使用

ASimpleCache使用起来太简单了,尤其是使用过SharePreference。

1.1缓存字符串

首先,创建ASimpleCache对象:
[java]  view plain  copy
 
  1. //缓存  
  2. private ACache mACache;  
  3.   
  4. mACache = ACache.get(this);  
其次,存储数据:
[java]  view plain  copy
 
  1. mACache.put(Constants.KEY_STRING, result);  
还有,获取缓存数据:
[java]  view plain  copy
 
  1. String result = mACache.getAsString(Constants.KEY_STRING);  
最后,清除缓存:
[java]  view plain  copy
 
  1. mACache.remove(Constants.KEY_STRING);  

1.2缓存JsonObject

首先,创建ASimpleCache对象:
[java]  view plain  copy
 
  1. //缓存  
  2. private ACache mACache;  
  3.   
  4. mACache = ACache.get(this);  
其次,存储数据:
[java]  view plain  copy
 
  1. mACache.put(Constants.KEY_JSONOBJECT, jsonObject);  
还有,获取缓存数据:
[java]  view plain  copy
 
  1. JSONObject result = mACache.getAsJSONObject(Constants.KEY_JSONOBJECT);  
最后,清除缓存:
[java]  view plain  copy
 
  1. mACache.remove(Constants.KEY_JSONOBJECT);  

1.3缓存JsonArray

首先,创建ASimpleCache对象:
[java]  view plain  copy
 
  1. //缓存  
  2. private ACache mACache;  
  3.   
  4. mACache = ACache.get(this);  
其次,存储数据:
[java]  view plain  copy
 
  1. mACache.put(Constants.KEY_JSONARRAY, jsonArray);  
还有,获取缓存数据:
[java]  view plain  copy
 
  1. JSONArray result = mACache.getAsJSONArray(Constants.KEY_JSONARRAY);  
最后,清除缓存:
[java]  view plain  copy
 
  1. mACache.remove(Constants.KEY_JSONARRAY);  

1.4缓存Bitmap

首先,创建ASimpleCache对象:
[java]  view plain  copy
 
  1. //缓存  
  2. private ACache mACache;  
  3.   
  4. mACache = ACache.get(this);  
其次,存储数据:
[java]  view plain  copy
 
  1. Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);  
  2.         mACache.put(Constants.KEY_BITMAP, bitmap);  
还有,获取缓存数据:
[java]  view plain  copy
 
  1. Bitmap bitmap = mACache.getAsBitmap(Constants.KEY_BITMAP);  
最后,清除缓存:
[java]  view plain  copy
 
  1. mACache.remove(Constants.KEY_BITMAP);  

1.5缓存Drawable

首先,创建ASimpleCache对象:
[java]  view plain  copy
 
  1. //缓存  
  2. private ACache mACache;  
  3.   
  4. mACache = ACache.get(this);  
其次,存储数据:
[java]  view plain  copy
 
  1. Drawable drawable = getResources().getDrawable(R.mipmap.ic_launcher);  
  2.         mACache.put(Constants.KEY_DRAWABLE, drawable);  
还有,获取缓存数据:
[java]  view plain  copy
 
  1. Drawable bitmap = mACache.getAsDrawable(Constants.KEY_DRAWABLE);  
最后,清除缓存:
[java]  view plain  copy
 
  1. mACache.remove(Constants.KEY_DRAWABLE);  

1.6缓存序列化的java对象

首先,创建ASimpleCache对象:
[java]  view plain  copy
 
  1. //缓存  
  2. private ACache mACache;  
  3.   
  4. mACache = ACache.get(this);  
其次,存储数据:
[java]  view plain  copy
 
  1. mACache.put(Constants.KEY_JAVA_BEAN, mWeather);  
还有,获取缓存数据:
[java]  view plain  copy
 
  1. Weather result = (Weather) mACache.getAsObject(Constants.KEY_JAVA_BEAN);  
最后,清除缓存:
[java]  view plain  copy
 
  1. mACache.remove(Constants.KEY_JAVA_BEAN);  

1.7缓存byte数据

首先,创建ASimpleCache对象:
[java]  view plain  copy
 
  1. private ACache mACache;  
  2.   
  3. mACache = ACache.get(this);  
其次,存储数据:
[java]  view plain  copy
 
  1. private void saveByte() {  
  2.         OutputStream ostream = null;  
  3.         try {  
  4.             ostream = mACache.put(Constants.KEY_BYTE);  
  5.         } catch (FileNotFoundException e) {  
  6.             e.printStackTrace();  
  7.         }  
  8.         if (ostream == null) {  
  9.             ToastUtil.simpleToast(this"Open stream error!");  
  10.             return;  
  11.         }  
  12.         try {  
  13.             URL u = new URL(Constants.downloadUrl);  
  14.             HttpURLConnection conn = (HttpURLConnection) u.openConnection();  
  15.             conn.connect();  
  16.             InputStream stream = conn.getInputStream();  
  17.             byte[] buff = new byte[1024];  
  18.             int counter;  
  19.             while ((counter = stream.read(buff)) > 0) {  
  20.                 ostream.write(buff, 0, counter);  
  21.             }  
  22.         } catch (IOException e) {  
  23.             e.printStackTrace();  
  24.         } finally {  
  25.             try {  
  26.                 // cache update  
  27.                 ostream.close();  
  28.             } catch (IOException e) {  
  29.                 e.printStackTrace();  
  30.             }  
  31.             runOnUiThread(new Runnable() {  
  32.                 @Override  
  33.                 public void run() {  
  34.                     showTv.setText("done...");  
  35.                 }  
  36.             });  
  37.         }  
  38.     }  
还有,获取缓存数据:
[java]  view plain  copy
 
  1. private void getsByte() {  
  2.         InputStream stream = null;  
  3.         try {  
  4.             stream = mACache.get(Constants.KEY_BYTE);  
  5.         } catch (FileNotFoundException e) {  
  6.             e.printStackTrace();  
  7.         }  
  8.         if (stream == null) {  
  9.             ToastUtil.simpleToast(this"Bitmap cache is null ...");  
  10.             showTv.setText("file not found");  
  11.             return;  
  12.         }  
  13.         try {  
  14.             showTv.setText("file size: " + stream.available());  
  15.         } catch (IOException e) {  
  16.             showTv.setText("error " + e.getMessage());  
  17.         }  
  18.     }  
最后,清除缓存:
[java]  view plain  copy
 
  1. mACache.remove(Constants.KEY_BYTE);  

 

觉得不错的话,记得打赏一下:

https://blog.csdn.net/shenggaofei/article/details/105873568

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值