Android图片缓存加强版(LruCache+DiskLruCache+软引用)

本文介绍了一种结合LruCache、DiskLruCache及软引用的图片缓存方案,旨在提高图片加载效率,减少网络请求次数。策略包括内存缓存、软引用缓存以及磁盘缓存,以确保图片能在不同情况下快速加载。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

将LruCache+DiskLruCache+软引用三种缓存技术结合起来,加强图片的缓存效果。

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Environment;
import android.support.v4.util.LruCache;

import com.jakewharton.disklrucache.DiskLruCache;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.SoftReference;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedHashMap;

public class ImageCache {
    private static final String IMAGE_PATH = "image";
    private static final int DEFAULT_MEM_CACHE_SIZE = 1024 * 1024 * 8;
    private static final int DEFAULT_DIS_CACHE_SIZE = 1024 * 1024 * 10;
    private static final int DEDAULT_SOFT_CACHE_NUM = 20;

    private LruCache<String, Bitmap> mLruCache;
    private DiskLruCache mDisLruCache;
    private LinkedHashMap<String, SoftReference<Bitmap>> mSoftCache;

    private volatile static ImageCache mImageCache;

    private ImageCache(Context context) {
        mLruCache = new LruCache<String,Bitmap>(DEFAULT_MEM_CACHE_SIZE) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                return getBitmapSize(value);
            }

            @Override
            protected void entryRemoved(boolean evicted, String key, Bitmap oldValue, Bitmap newValue) {
                if (evicted) {
                    mSoftCache.put(key, new SoftReference<Bitmap>(oldValue));
                }
                super.entryRemoved(evicted, key, oldValue, newValue);
            }
        };

        try {
            mDisLruCache.open(getDiskCacheDir(context), getAppVersion(context), 1, DEFAULT_DIS_CACHE_SIZE);
        } catch (IOException e) {
            e.printStackTrace();
        }


        mSoftCache = new LinkedHashMap<String, SoftReference<Bitmap>>(
                DEDAULT_SOFT_CACHE_NUM, 0.75f, true) {
            private static final long serialVersionUID = 1L;
            /**
             * 当软引用数量大于20的时候,最旧的软引用将会被从链式哈希表中移出
             */
            @Override
            protected boolean removeEldestEntry(
                    Entry<String, SoftReference<Bitmap>> eldest) {
                if (size() > DEDAULT_SOFT_CACHE_NUM) {
                    return true;
                }
                return false;
            }
        };

    }

    public static ImageCache getInstance(Context context) {
        if (mImageCache == null) {
            synchronized (ImageCache.class) {
                if (mImageCache == null) {
                    mImageCache = new ImageCache(context);
                }
            }
        }
        return mImageCache;
    }

    /*
    * 查看缓存是否存在key的图片,
    * 在从网络获取图片之前可以先进行查看,如果没有就网络请求
    *
    * 策略:先查看mLruCache是否存在该实例对象,即查看内存是否存在该对象
    *      再查看mSoftCache是否存在,即查看mLruCache中被回收的对象中是否存在该对象
    *      最后查看Disk中是否缓存了该对象
    * 
    * */
    public Bitmap get(String key) {
        key = hashKey(key);

        DiskLruCache.Snapshot snapshot = null;
        Bitmap bitmap = mLruCache.get(key);

        if (bitmap == null) {
            bitmap = mSoftCache.get(key).get();

            if (bitmap == null) {
                if (mDisLruCache != null) {
                    try {
                        snapshot = mDisLruCache.get(key);

                        if (snapshot != null) {
                            InputStream is = snapshot.getInputStream(0);
                            bitmap = BitmapFactory.decodeStream(is);
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            } else {
                mSoftCache.remove(key);
            }

            if (bitmap != null) {
                mLruCache.put(key, bitmap);
            }
        }

        return bitmap;
    }

    /*
    * 从网络获取到图片资源之后,就调用该方法将它进行缓存,
    * */
    public void put(String key, Bitmap bitmap) {
        key = hashKey(key);

        mLruCache.put(key, bitmap);

        if (mDisLruCache != null) {
            try {
                DiskLruCache.Editor editor = mDisLruCache.edit(key);

                if (editor != null) {
                    OutputStream outputStream = editor.newOutputStream(0);
                    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
                    outputStream.write(byteArrayOutputStream.toByteArray());
                    editor.commit();
                    mDisLruCache.flush();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /*
    * 获取图片大小
    * */
    private int getBitmapSize(Bitmap bitmap) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1) {
            return bitmap.getByteCount();
        }
        return bitmap.getRowBytes() * bitmap.getHeight();
    }

    /*
    * 得到Disk缓存目标
    * */
    private File getDiskCacheDir(Context context) {
        String cachePath;
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            cachePath = context.getExternalCacheDir().getPath();
        } else {
            cachePath = context.getCacheDir().getPath();
        }

        return new File(cachePath + File.separator + IMAGE_PATH);
    }

    /*
    * 获取应用版本号
    * */
    private int getAppVersion(Context context) {
        try {
            PackageInfo info = context.getPackageManager().getPackageInfo(context.getPackageName(),0);
            return info.versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return 1;
    }

    /*
    * 将key编码为MD5
    * */
    private String hashKey(String key) {
        String cacheKey;

        MessageDigest digest = null;
        try {
            digest = MessageDigest.getInstance("MD5");
            digest.update(key.getBytes());
            cacheKey = bytesToHexString(digest.digest());
        } catch (NoSuchAlgorithmException e) {
            cacheKey = String.valueOf(key.hashCode());
            e.printStackTrace();
        }
        return cacheKey;

    }

    private String bytesToHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(0xFF & bytes[i]);
            if (hex.length() == 1) {
                sb.append('0');
            }
            sb.append(hex);
        }
        return sb.toString();
    }
}

参考文章:
Android图片缓存技术

android中图片的三级cache策略(内存、文件、网络)之二:内存缓存策略

### 如何在Linux系统中使用Telnet命令连接到指定端口 在Linux系统中,`telnet` 是一种用于远程登录和网络调试的工具。其基本功能之一是可以用来测试特定主机上的某个端口是否开放并可访问。 #### Telnet命令的基本语法 `telnet` 的基础语法如下: ```bash telnet [-468EKLadr] [-Xa authtype] [-b hostalias] [-e escapechar] [-l user] [-n tracefile] [host [port]] ``` 其中 `host` 表示目标服务器地址,可以是域名或IP地址;`port` 则表示要连接的目标端口号[^1]。 #### 连接到指定端口的具体方法 假设需要测试 IP 地址为 `192.168.120.206` 的设备上是否有服务监听于端口 `80`,可以通过以下方式执行: ```bash telnet 192.168.120.206 80 ``` 如果该端口未被占用或者防火墙阻止,则会收到类似于下面的消息: ``` Trying 192.168.120.206... telnet: connect to address 192.168.120.206: Connection refused telnet: Unable to connect to remote host: Connection refused ``` 这表明无法成功建立连接[^2]。 当尝试连接至已开启的服务时(比如HTTP默认使用的80端口),可能会看到类似这样的响应: ``` Trying 192.168.x.y... Connected to www.example.com. Escape character is '^]'. ``` 此时已经建立了与目标机器相应端口之间的通信链路。 #### 开启Telnet服务及配置防火墙规则 为了能够正常接收来自其他计算机发起的telnet请求,在本地也需要确保安装有支持此协议的应用程序以及调整好安全策略设置。例如对于CentOS/RHEL类发行版而言,默认情况下可能并未预装客户端/服务器组件,需手动添加: ```bash yum install telnet* ``` 接着按照需求修改SELinux状态或将对应流量加入例外列表里去——即允许外部访问TCP第23号标准shell交互界面入口处。另外还需记得更新包管理器缓存同步最新补丁版本信息后再操作实际部署环境前先做好充分准备以免造成不必要的麻烦哦! 最后一步便是向数据包过滤子系统追加准入条件语句来放行入站方向针对上述提及过的知名编号所对应的业务逻辑处理单元之间相互作用所产生的合法报文交换活动了。 ```bash iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 23 -j ACCEPT service iptables save && service iptables restart ``` 以上指令序列的作用在于永久生效地把匹配条件满足的新建型态下的TCP三次握手初始SYN标志位置位正确的数据帧对象纳入白名单范畴之内从而实现自动化运维流程简化管理工作量提升效率减少人为失误概率的目的[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值