Android中图片的三级缓存介绍及实现

最后,简单粗暴的一句话概括:**

**Picasso所能实现的功能,Glide都能做,无非是所需的设置不同。但是Picasso体积比起Glide小太多如果项目中网络请求本身用的就是okhttp或者retrofit(本质还是okhttp),那么建议用Picasso,体积会小很多(Square全家桶的干活)。

Glide的好处是大型的图片流,比如gif、Video,如果你们是做美拍、爱拍这种视频类应用,建议使用。

Fresco在5.0以下的内存优化非常好,代价就是体积也非常的大,按体积算Fresco>Glide>Picasso不过在使用起来也有些不便(小建议:他只能用内置的一个ImageView来实现这些功能,用起来比较麻烦,我们通常是根据Fresco自己改改,直接使用他的Bitmap层)

**

下面具体讲解图片三级缓存是哪三级?(Picasso 和 Glide 和 Fresco 基本也是这 三级)

原文:https://www.cnblogs.com/RabbitLx/p/5792268.html

我们不能每次加载图片的时候都让用户从网络上下载,这样不仅浪费流量又会影响用户体验,所以Android中引入了图片的缓存这一操作机制。

原理:

首先根据图片的网络地址在网络上下载图片,将图片先缓存到内存缓存中,缓存到强引用中 也就是LruCache中。

如果强引用中空间不足,就会将较早存储的图片对象驱逐到软引用(softReference)中存储,然后将图片缓存到文件(内部存储外部存储)中;读取图片的时候,先读取内存缓存,判断强引用中是否存在图片,如果强引用中存在,则直接读取

如果强引用中不存在,则判断软引用中是否存在,如果软引用中存在,则将软引用中的图片添加到强引用中并且删除软引用中的数据

如果软引用中不存在,则读取文件存储,如果文件存储不存在,则网络加载。

下载: 网络–内存–文件

读取: 内存–强引用–软引用–文件–网络

也就是这样的一个过程,下面用一个简单地demo来演示一下图片你的三级缓存,此demo中只有一个界面,界面上一个ImageView用来显示图片,一个按钮用来点击的时候加载图片。布局如下:

复制代码


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

 2 <RelativeLayout xmlns:android\="http://schemas.android.com/apk/res/android"

 3     android:layout\_width\="match\_parent"

 4     android:layout\_height\="match\_parent"

 5     \>

 6     <ImageView

 7         android:id\="@+id/iv\_img"

 8         android:layout\_width\="wrap\_content"

 9         android:layout\_height\="wrap\_content"

10         android:src\="@mipmap/ic\_launcher"

11         android:layout\_centerInParent\="true"/>

12     <Button

13         android:id\="@+id/btn\_download"

14         android:layout\_below\="@+id/iv\_img"

15         android:layout\_centerHorizontal\="true"

16         android:layout\_width\="wrap\_content"

17         android:layout\_height\="wrap\_content"

18         android:text\="加载图片"/>

19 

20 </RelativeLayout\>

复制代码

因为要从网络下载数据,还要存储到本地sd卡中,所以不要忘了为程序添加网络访问的权限、网络状态访问的权限和向外部存储设备写内容的权限:


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

2     <uses-permission android:name="android.permission.ACCESS\_NETWORK\_STATE" />

3     <uses-permission android:name="android.permission.WRITE\_EXTERNAL\_STORAGE" />

接着,创建一个 HttpUtils 工具类用于访问网络,代码如下:

复制代码


 1 package com.yztc.lx.cashimg; 2 

 3 import android.content.Context; 4 import android.net.ConnectivityManager; 5 import android.net.NetworkInfo; 6 

 7 import java.io.ByteArrayOutputStream; 8 import java.io.IOException; 9 import java.io.InputStream;

10 import java.net.HttpURLConnection;

11 import java.net.URL;

12 

13 /\*\*网络访问工具类

14 \* Created by Lx on 2016/8/19.

15  \*/

16 

17 public class HttpUtils {

18     /\*\*

19 \* 判断网络连接是否通畅

20 \* @param mContext

21 \* @return

22      \*/

23     public static boolean isNetConn(Context mContext) {

24         ConnectivityManager manager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY\_SERVICE);

25         NetworkInfo info = manager.getActiveNetworkInfo();

26         if (info != null) {

27             return info.isConnected();

28         } else {

29             return false;

30 }

31 }

32 

33     /\*\*

34 \* 根据path下载网络上的数据

35 \* @param path  路径

36 \* @return  返回下载内容的byte数据形式

37      \*/

38     public static byte\[\] getDateFromNet(String path) {

39         ByteArrayOutputStream baos = new ByteArrayOutputStream();

40         try {

41             URL url = new URL(path);

42             HttpURLConnection conn = (HttpURLConnection) url.openConnection();

43             conn.setRequestMethod("GET");

44             conn.setConnectTimeout(5000);

45             conn.setDoInput(true);

46 conn.connect();

47             if (conn.getResponseCode()==200) {

48                 InputStream is = conn.getInputStream();

49                 byte b\[\] = new byte\[1024\];

50                 int len;

51                 while ((len=is.read(b))!=-1) {

52                     baos.write(b, 0, len);

53 }

54                 return baos.toByteArray();

55 }

56         } catch (IOException e) {

57 e.printStackTrace();

58 }

59         return baos.toByteArray();

60 }

61 

62 }

复制代码

还有操作外部存储的工具类:

复制代码


 1 package com.yztc.lx.cashimg; 2 

 3 import android.graphics.Bitmap; 4 import android.graphics.BitmapFactory; 5 import android.os.Environment; 6 

 7 import java.io.ByteArrayOutputStream; 8 import java.io.File; 9 import java.io.FileInputStream;

10 import java.io.FileOutputStream;

11 import java.io.IOException;

12 

13 /\*\*

14 \* Created by Lx on 2016/8/20.

15  \*/

16 

17 public class ExternalStorageUtils {

18     /\*\*

19 \* 将传递过来的图片byte数组存储到sd卡中

20 \* @param imgName  图片的名字

21 \* @param buff  byte数组

22 \* @return  返回是否存储成功

23      \*/

24     public static boolean storeToSDRoot(String imgName, byte buff\[\]) {

25         boolean b = false;

26         String basePath = Environment.getExternalStorageDirectory().getAbsolutePath();

27         File file = new File(basePath, imgName);

28         try {

29             FileOutputStream fos = new FileOutputStream(file);

30 fos.write(buff);

31 fos.close();

32             b = true;

33         } catch (IOException e) {

34 e.printStackTrace();

35 }

36         return b;

37 }

38 

39     /\*\*

40 \* 从本地内存中根据图片名字获取图片

41 \* @param imgName  图片名字

42 \* @return  返回图片的Bitmap格式

43      \*/

44     public static Bitmap getImgFromSDRoot(String imgName) {

45         Bitmap bitmap = null;

46         String basePath = Environment.getExternalStorageDirectory().getAbsolutePath();

47         File file = new File(basePath, imgName);

48         try {

49             FileInputStream fis = new FileInputStream(file);

50             ByteArrayOutputStream baos = new ByteArrayOutputStream();

51             byte b\[\] = new byte\[1024\];

52             int len;

53             while ((len = fis.read(b)) != -1) {

54                 baos.write(b, 0, len);

55 }

56             byte buff\[\] = baos.toByteArray();

57             if (buff != null && buff.length != 0) {

58                 bitmap = BitmapFactory.decodeByteArray(buff, 0, buff.length);

59 }

60         } catch (IOException e) {

61 e.printStackTrace();

62 }

63         return bitmap;

64 }

65 

66 

67 }

复制代码

本例中将图片默认存在了sd卡根目录中。

然后是最主要的主函数了:

复制代码


  1 package com.yztc.lx.cashimg;  2 

  3 import android.graphics.Bitmap;  4 import android.graphics.BitmapFactory;  5 import android.os.Bundle;  6 import android.os.Handler;  7 import android.os.Message;  8 import android.support.v7.app.AppCompatActivity;  9 import android.util.Log; 10 import android.util.LruCache; 11 import android.view.View; 12 import android.widget.Button; 13 import android.widget.ImageView; 14 import android.widget.Toast; 15 

 16 import java.lang.ref.SoftReference; 17 import java.util.LinkedHashMap; 18 

 19 public class MainActivity extends AppCompatActivity implements View.OnClickListener { 20 

 21     private Button btn\_download; 22     private ImageView iv\_img; 23     private MyLruCache myLruCache; 24     private LinkedHashMap<String, SoftReference<Bitmap>> cashMap = new LinkedHashMap<>();

 25     private static final String TAG = "MainActivity";

 26     private String imgPath = "http://www.3dmgame.com/UploadFiles/201212/Medium\_20121217143424221.jpg";

 27     private Handler handler = new Handler() { 28         @Override

 29         public void handleMessage(Message msg) { 30             Bitmap bitmap = (Bitmap) msg.obj; 31             iv\_img.setImageBitmap(bitmap);

 32             Toast.makeText(MainActivity.this, "从网络上下载图片", Toast.LENGTH\_SHORT).show();

 33         }

 34     };

 35 

 36     @Override

 37     protected void onCreate(Bundle savedInstanceState) { 38         super.onCreate(savedInstanceState);

 39         setContentView(R.layout.activity\_main);

 40         initView();

 41         int totalMemory = (int) Runtime.getRuntime().maxMemory();

 42         int size = totalMemory / 8;

 43         myLruCache = new MyLruCache(size); 44         btn\_download.setOnClickListener(this);

 45     }

 46 

 47     private void initView() { 48         btn\_download = (Button) findViewById(R.id.btn\_download); 49         iv\_img = (ImageView) findViewById(R.id.iv\_img); 50     }

 51 

 52     @Override

 53     public void onClick(View v) { 54         Bitmap b = getImgCache(); 55         if (b != null) {

 56             iv\_img.setImageBitmap(b);

 57         } else { 58             new Thread(new Runnable() { 59                 @Override

 60                 public void run() { 61                     if (HttpUtils.isNetConn(MainActivity.this)) {

 62                         byte b\[\] = HttpUtils.getDateFromNet(imgPath); 63                         if (b != null && b.length != 0) {

 64                             Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);

 65                             Message msg = Message.obtain(); 66                             msg.obj = bitmap; 67                             handler.sendMessage(msg);

 68                             myLruCache.put(imgPath, bitmap);

 69                             Log.d(TAG, "run: " + "缓存到强引用中成功");

 70                             boolean bl = ExternalStorageUtils.storeToSDRoot("haha.jpg", b);

 71                             if (bl) { 72                                 Log.d(TAG, "run: " + "缓存到本地内存成功");

 73                             } else { 74                                 Log.d(TAG, "run: " + "缓存到本地内存失败");

 75                             }

 76                         } else { 77                             Toast.makeText(MainActivity.this, "下载失败!", Toast.LENGTH\_SHORT).show();

 78                         }

 79 

 80                     } else { 81                         Toast.makeText(MainActivity.this, "请检查你的网络!", Toast.LENGTH\_SHORT).show();

 82                     }

 83                 }

 84             }).start();

 85         }

 86     }

 87 

 88     /\*\*

 89      \* 从缓存中获取图片

 90      \*

 91 \* @return 返回获取到的Bitmap 92      \*/

 93     public Bitmap getImgCache() { 94         Bitmap bitmap = myLruCache.get(imgPath); 95         if (bitmap != null) {

 96             Log.d(TAG, "getImgCache: " + "从LruCache获取图片");

 97         } else { 98             SoftReference<Bitmap> sr = cashMap.get(imgPath); 99             if (sr != null) {

100                 bitmap = sr.get();

101 myLruCache.put(imgPath, bitmap);

102 cashMap.remove(imgPath);

103                 Log.d(TAG, "getImgCache: " + "从软引用获取图片");

104             } else {

105                 bitmap = ExternalStorageUtils.getImgFromSDRoot("haha.jpg");

106                 Log.d(TAG, "getImgCache: " + "从外部存储获取图片");

107 }

108 }

109         return bitmap;

110 }

111 

112     /\*\*

113 \* 自定义一个方法继承系统的LruCache方法

114      \*/

ence<Bitmap> sr = cashMap.get(imgPath); 99             if (sr != null) {

100                 bitmap = sr.get();

101 myLruCache.put(imgPath, bitmap);

102 cashMap.remove(imgPath);

103                 Log.d(TAG, "getImgCache: " + "从软引用获取图片");

104             } else {

105                 bitmap = ExternalStorageUtils.getImgFromSDRoot("haha.jpg");

106                 Log.d(TAG, "getImgCache: " + "从外部存储获取图片");

107 }

108 }

109         return bitmap;

110 }

111 

112     /\*\*

113 \* 自定义一个方法继承系统的LruCache方法

114      \*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值