安卓面经_Anroid面经(26/30)缓存机制全解析

牛客高级系列专栏:

安卓(安卓系统开发也要掌握)


嵌入式


本人是2020年毕业于广东工业大学研究生:许乔丹,有国内大厂CVTE和世界500强企业安卓开发经验,该专栏整理本人对常见安卓高频开发面试题的理解;

网上安卓资料千千万,笔者将继续维护专栏,一杯奶茶价格不止提供答案解析,承诺提供专栏内容免费技术答疑,直接咨询即可。助您提高安卓面试准备效率,为您面试保驾护航!

正文开始⬇

缓存机制在实际工作暂时较少接触,但还是有必要学习一下,面试可能会问到。面试官可能会问:

  1. 你了解Android中的缓存机制吗?⭐⭐⭐⭐
  2. LruCache的源码看过吗?⭐⭐⭐
  3. 还有用过哪些缓存工具?⭐⭐⭐⭐

看完以下的解析,一定可以让面试官眼前一亮。

目录

  • 1、Android中的缓存机制
  • 2、LruCache的使用
    • 2.1 LruCache使用实例
    • 2.2 LruCache的实现原理
    • 2.3 LruCache源码分析
      • 2.3.1 增加缓存对象
      • 2.3.2 获取缓存对象
  • 3、DiskLruCache
  • 4、ASimpleCache

1、Android中的缓存机制

现在大家的流量确实增加了wifi普及率也提高了,但每次请求网络还是会出现网络卡顿和延迟现象,给用户造成不好体验,因此缓存机制还是有必要的。通过缓存策略,我们不需要每次都从网上请求图片或从存储设备中加载图片,这样就极大地提高了图片的加载效率以及用户体验。

相对于数据库的增删改查,缓存机制一般也包括缓存的增加、获取、删除三大功能。我们可以增加和获取所需要的缓存,同时,当缓存空间超过设定值,则会删除一些可能不需要的缓存数据以添加新的缓存数据。

LRU(Least Recently Used)缓存算法应运而生。其核心思想就是当缓存满了,会优先删除最早添加,并且最近使用最少的缓存对象。举个例子,我们依次往缓存里存放了[1-5],共5个数据,此时如果要删除数据,则会按照1-2-3-4-5的顺序删除。但是我们又从缓存区获取了第[2]个对象,那么此时如果要删除数据,则会按照1-3-4-5-2的顺序删除,具体代码可见2.2小节。

采用LRU算法的缓存有两种:LruCache和DisLruCache,前者实现了内存缓存,后者实现了磁盘缓存。当然,说到磁盘缓存,很多人会想到数据库以及Sharedpreference等作持久化处理,这当然是可以的。同时,LruCache和DisLruCache配合起来用效果还会更好。现在先来看看LruCache吧。

2、LruCache的使用

LruCache是Android3.1提供的一个缓存类,也就是Android自带的类,只要import android.util.LruCache 就可以直接使用。LruCache是个泛型类,主要算法原理是把最近使用的对象用强引用(即我们平常使用的对象引用方式)存储在 LinkedHashMap(2.2小节会介绍)中。当缓存满时,把最近最少使用的对象从内存中移除,并提供了get和put方法来完成缓存的获取和添加操作。

2.1 LruCache使用实例

如果需要缓存图片,可以这么写:

int maxMemory = (int) (Runtime.getRuntime().totalMemory() / 1024);
int cacheSize = maxMemory / 8;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
    @Override
    protected int sizeOf(String key, Bitmap value) {
        return value.getRowBytes() * value.getHeight() / 1024;
    }
};

一般来说,缓存区的大小建议设置为当前进程可用内存的1/8。接着重新sizeOf()方法以便计算出每张图片的大小。最后要特别注意,申请的缓存区大小和每个缓存对象的大小所用的单位要保持一致。

2.2 LruCache的实现原理

正如第1节所述,LruCache会有一个队列,实现优先删除最早添加,并且最近使用最少的缓存对象。而这个队列就是由LinkedHashMap所维护。LinkedHashMap是由数组+双向链表的数据结构实现的。可以通过以下构造函数指定LinkedHashMap的双向链表是按访问数据还是插入顺序排列。

public LinkedHashMap(int initialCapacity,
	float loadFactor,
	boolean accessOrder) {
	super(initialCapacity, loadFactor);
	this.accessOrder = accessOrder;
}

当accessOrder变量为true时,LinkedHashMap为访问顺序,为false时LinkedHashMap为插入顺序。将第1节的例子用代码描述如下:

public void test() {
	LinkedHashMap<Integer, Integer> map = new LinkedHashMap<>(0, 0.75f, true);
	map.put(1, 1);
	map.put(2, 2);
	map.put(3, 3);
	map.put(4, 4);
	map.put(5, 5);
	map.get(2);

	for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
		System.out.println(entry.getKey() + ":" + entry.getValue());

	}
}

最后打印出来的结果正是 1:1 3:3 4:4 5:5 2:2

其中1是最先添加且最近也没有使用过的变量,则排在第1位,此时需要需要删除缓存对象,则优先删除1。2是最近刚使用过的对象,则排在最后输出,也是最后删除的对象。LinkedHashMap这样的逻辑刚好满足LRU缓存算法的思想。因此可以说LurCache的巧妙实现就是利用了LinkedHashMap的结构特性。

2.3 LruCache源码分析

首先看看LruCache的构造函数

// LruCache.java
public LruCache(int maxSize) {
	if (maxSize <= 0) {
		throw new IllegalArgumentException("maxSize <= 0");
	}
	this.maxSize = maxSize;
	this.map = new LinkedHashMap<K, V>(0, 0.75f, true); //1
}

在[注释1]可以明显看到LruCache正是使用了LinkedHashMap的访问顺序。

2.3.1 增加缓存对象

增加缓存使用put()方法:

// LruCache.java
 public final V put(K key, V value) {
        // 输入不可为空
        if (key == null || value == null) {
            throw new NullPointerException("key == nu

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

Android高频面试题全解析 文章被收录于专栏

#提供免费售后答疑!!花一杯奶茶的钱获得安卓面试答疑服务,稳赚不赔# Android发展已经很多年,安卓资料网上千千万,本专栏免费提供专栏内容技术答疑!!私聊当天必回。在阅读过程或者其他安卓学习过程有疑问,都非常欢迎私聊交流。

全部评论
正好最近面Android需要,谢谢
点赞 回复 分享
发布于 2023-03-05 12:39 广东
请继续更下去,作者
点赞 回复 分享
发布于 2023-03-05 13:06 湖北

相关推荐

3 4 评论
分享
牛客网
牛客企业服务