android图片的缓存机制,Android中图片的三级缓存机制

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

原理:

首先根据图片的网络地址在网络上下载图片,将图片先缓存到内存缓存中,缓存到强引用中 也就是LruCache中。如果强引用中空间不足,就会将较早存储的图片对象驱逐到软引用(softReference)中存储,然后将图片缓存到文件(内部存储外部存储)中;读取图片的时候,先读取内存缓存,判断强引用中是否存在图片,如果强引用中存在,则直接读取,如果强引用中不存在,则判断软引用中是否存在,如果软引用中存在,则将软引用中的图片添加到强引用中并且删除软引用中的数据,如果软引用中不存在,则读取文件存储,如果文件存储不存在,则网络加载。

下载: 网络--内存--文件

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

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

android:layout_width="match_parent"

android:layout_height="match_parent"

>

android:id="@+id/iv_img"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:src="@mipmap/ic_launcher"

android:layout_centerInParent="true"/>

android:id="@+id/btn_download"

android:layout_below="@+id/iv_img"

android:layout_centerHorizontal="true"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

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

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

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

package com.yztc.lx.cashimg;

import android.content.Context;

import android.net.ConnectivityManager;

import android.net.NetworkInfo;

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.net.HttpURLConnection;

import java.net.URL;

/**网络访问工具类

* Created by Lx on 2016/8/19.

*/

public class HttpUtils {

/**

* 判断网络连接是否通畅

* @param mContext

* @return

*/

public static boolean isNetConn(Context mContext) {

ConnectivityManager manager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);

NetworkInfo info = manager.getActiveNetworkInfo();

if (info != null) {

return info.isConnected();

} else {

return false;

}

}

/**

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

* @param path 路径

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

*/

public static byte[] getDateFromNet(String path) {

ByteArrayOutputStream baos = new ByteArrayOutputStream();

try {

URL url = new URL(path);

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

conn.setRequestMethod("GET");

conn.setConnectTimeout(5000);

conn.setDoInput(true);

conn.connect();

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

InputStream is = conn.getInputStream();

byte b[] = new byte[1024];

int len;

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

baos.write(b, 0, len);

}

return baos.toByteArray();

}

} catch (IOException e) {

e.printStackTrace();

}

return baos.toByteArray();

}

}

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

package com.yztc.lx.cashimg;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.os.Environment;

import java.io.ByteArrayOutputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

/**

* Created by Lx on 2016/8/20.

*/

public class ExternalStorageUtils {

/**

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

* @param imgName 图片的名字

* @param buff byte数组

* @return 返回是否存储成功

*/

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

boolean b = false;

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

File file = new File(basePath, imgName);

try {

FileOutputStream fos = new FileOutputStream(file);

fos.write(buff);

fos.close();

b = true;

} catch (IOException e) {

e.printStackTrace();

}

return b;

}

/**

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

* @param imgName 图片名字

* @return 返回图片的Bitmap格式

*/

public static Bitmap getImgFromSDRoot(String imgName) {

Bitmap bitmap = null;

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

File file = new File(basePath, imgName);

try {

FileInputStream fis = new FileInputStream(file);

ByteArrayOutputStream baos = new ByteArrayOutputStream();

byte b[] = new byte[1024];

int len;

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

baos.write(b, 0, len);

}

byte buff[] = baos.toByteArray();

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

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

}

} catch (IOException e) {

e.printStackTrace();

}

return bitmap;

}

}

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

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

package com.yztc.lx.cashimg;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.os.Bundle;

import android.os.Handler;

import android.os.Message;

import android.support.v7.app.AppCompatActivity;

import android.util.Log;

import android.util.LruCache;

import android.view.View;

import android.widget.Button;

import android.widget.ImageView;

import android.widget.Toast;

import java.lang.ref.SoftReference;

import java.util.LinkedHashMap;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

private Button btn_download;

private ImageView iv_img;

private MyLruCache myLruCache;

private LinkedHashMap> cashMap = new LinkedHashMap<>();

private static final String TAG = "MainActivity";

private String imgPath = "http://www.3dmgame.com/UploadFiles/201212/Medium_20121217143424221.jpg";

private Handler handler = new Handler() {

@Override

public void handleMessage(Message msg) {

Bitmap bitmap = (Bitmap) msg.obj;

iv_img.setImageBitmap(bitmap);

Toast.makeText(MainActivity.this, "从网络上下载图片", Toast.LENGTH_SHORT).show();

}

};

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

initView();

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

int size = totalMemory / 8;

myLruCache = new MyLruCache(size);

btn_download.setOnClickListener(this);

}

private void initView() {

btn_download = (Button) findViewById(R.id.btn_download);

iv_img = (ImageView) findViewById(R.id.iv_img);

}

@Override

public void onClick(View v) {

Bitmap b = getImgCache();

if (b != null) {

iv_img.setImageBitmap(b);

} else {

new Thread(new Runnable() {

@Override

public void run() {

if (HttpUtils.isNetConn(MainActivity.this)) {

byte b[] = HttpUtils.getDateFromNet(imgPath);

if (b != null && b.length != 0) {

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

Message msg = Message.obtain();

msg.obj = bitmap;

handler.sendMessage(msg);

myLruCache.put(imgPath, bitmap);

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

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

if (bl) {

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

} else {

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

}

} else {

Toast.makeText(MainActivity.this, "下载失败!", Toast.LENGTH_SHORT).show();

}

} else {

Toast.makeText(MainActivity.this, "请检查你的网络!", Toast.LENGTH_SHORT).show();

}

}

}).start();

}

}

/**

* 从缓存中获取图片

*

* @return 返回获取到的Bitmap

*/

public Bitmap getImgCache() {

Bitmap bitmap = myLruCache.get(imgPath);

if (bitmap != null) {

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

} else {

SoftReference sr = cashMap.get(imgPath);

if (sr != null) {

bitmap = sr.get();

myLruCache.put(imgPath, bitmap);

cashMap.remove(imgPath);

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

} else {

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

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

}

}

return bitmap;

}

/**

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

*/

public class MyLruCache extends LruCache {

/**

* 必须重写的构造函数,定义强引用缓存区的大小

* @param maxSize for caches that do not override {@link #sizeOf}, this is

* the maximum number of entries in the cache. For all other caches,

* this is the maximum sum of the sizes of the entries in this cache.

*/

public MyLruCache(int maxSize) {

super(maxSize);

}

//返回每个图片的大小

@Override

protected int sizeOf(String key, Bitmap value) {

//获取当前变量每行的字节数和行高度(基本是固定写法,记不住给我背!)

return value.getRowBytes() * value.getHeight();

}

/**

* 当LruCache中的数据被驱逐或是移除时回调的函数

*

* @param evicted 当LruCache中的数据被驱逐用来给新的value倒出空间的时候变化

* @param key 用来标示对象的键,一般put的时候传入图片的url地址

* @param oldValue 之前存储的旧的对象

* @param newValue 存储的新的对象

*/

@Override

protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {

if (evicted) {

/**

* 将旧的值存到软引用中,因为强引用中可能有多个值被驱逐,

* 所以创建一个LinkedHashMap>来存储软引用

* 基本也是固定写法

*/

SoftReference softReference = new SoftReference(oldValue);

cashMap.put(key, softReference);

}

}

}

}

基本的思路都在代码注释中写的很详细了,主要就是要自定义一个类,来继承系统的LruCache,实现其中的两个主要的方法sizeOf()和entryRemoved(),还有就是必须重写它的构造函数。

以上所述是小编给大家介绍的Android中图片的三级缓存机制的全部叙述,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的,在此也非常感谢大家对脚本之家网站的支持!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
用于类似图库,缓存,所困、缩略图 package com.example.cache; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.lang.ref.SoftReference; import java.util.HashMap; import java.util.Map; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.BitmapFactory.Options; import android.util.DisplayMetrics; /** * 1.从内存加载 * 2.本地缓存加载 * 3.本地加载 * @author Administrator * */ public class LoadCacheImageTool { private Activity activity; private Map<String,SoftReference> cacheMap; public LoadCacheImageTool(Activity activity){ this.activity = activity; this.cacheMap = new HashMap<String, SoftReference>(); } public Bitmap loadCacheImage(String imagePath){ Bitmap bitmap = null; if (cacheMap.containsKey(imagePath)) { bitmap = cacheMap.get(imagePath).get(); if (bitmap!=null) { return bitmap; } } bitmap = loadLocalCacheImage(imagePath); cacheMap.put(imagePath, new SoftReference(bitmap)); return bitmap; } ///mnt/sdcard/bk.png ///mnt/sdcard/cache/bk.png.cache private Bitmap loadLocalCacheImage(String imagePath) { Bitmap bitmap = null; String cacheImagePath = getCacheImagePath(imagePath); File cacheFile = new File(cacheImagePath); if (!cacheFile.exists()) { bitmap = loadLocalBigImage(imagePath); saveToCacheDir(bitmap,cacheImagePath); }else{ try { bitmap = BitmapFactory.decodeStream(new FileInputStream(cacheFile)); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return bitmap; } private String getCacheImagePath(String imagePath) { String cacheDir = new File(imagePath).getParent()+"/cache/"; if (!new File(cacheDir).exists()) { new File(cacheDir).mkdirs(); } String newImageName = new File(imagePath).getName()+".cache"; String newImagePath = cacheDir+newImageNam

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值